web-dev-qa-db-fra.com

c ++ Initialisation d'une structure avec un tableau en tant que membre

Modifié à nouveau car il n'était pas clair à l'origine que j'essaie d'initialiser les tableaux au moment de la compilation, pas au moment de l'exécution ...


J'ai le testcase réduit suivant:

typedef struct TestStruct
{
    int length;
    int values[];
};

TestStruct t = {3, {0, 1, 2}};
TestStruct t2 = {4, {0, 1, 2, 3}};

int main()
{
    return(0);
}

Cela fonctionne avec Visual C++, mais ne compile pas avec g ++ sous linux. Quelqu'un peut-il m'aider à rendre portable ce type spécifique d'initialiseur?

Détails supplémentaires: la structure réelle avec laquelle je travaille a plusieurs autres valeurs int, et la longueur du tableau peut aller d'une seule entrée à plus de 1800 entrées.

EDIT: Je pense (mais je ne suis pas sûr) que ce n'est pas un problème VLA. Pour clarifier, j'essaye d'obtenir que le compilateur fasse le travail pour moi au moment de la compilation. La longueur du tableau au moment de l'exécution est constante. Toutes mes excuses si je me trompe; Je suis principalement un programmeur c #/Perl/Ruby qui est bloqué en maintenant cette application héritée ...

Toute aide très appréciée. Merci!

25
Drew Shafer

c ++ n'a pas le même membre de tableau flexible que le dernier élément que c99. Vous devez utiliser un std::vector si vous ne savez pas combien d'éléments ou si vous devez en spécifier combien.

EDIT: Vous avez dit dans votre édition que le tableau est une constante d'exécution, alors spécifiez la taille et cela devrait fonctionner correctement. g ++ n'a aucun problème avec le code suivant:

struct TestStruct { // note typedef is not needed */
    int length;
    int values[3]; // specified the size
};

TestStruct t = {3, {0, 1, 2}};

int main() {
    // main implicitly returns 0 if none specified
}

EDIT: pour répondre à votre commentaire, vous pouvez utiliser des modèles comme celui-ci:

template <int N>
struct TestStruct {
    int length;
    int values[N];
};

TestStruct<3> t3 = {3, {0, 1, 2}};
TestStruct<2> t2 = {2, {0, 1}};

int main() {}

Le seul problème est qu'il n'y a pas de moyen facile de mettre à la fois t2 et t3 dans un conteneur (comme une liste/vecteur/pile/file d'attente/etc parce qu'ils ont des tailles différentes. Si vous le souhaitez, vous devez utiliser std::vector. De plus, si vous faites cela, il n'est pas nécessaire de stocker la taille (elle est associée au type). Vous pouvez donc le faire à la place:

template <int N>
struct TestStruct {
    static const int length = N;
    int values[N];
};

TestStruct<3> t3 = {{0, 1, 2}};
TestStruct<2> t2 = {{0, 1}};

int main() {}

Mais encore une fois, vous ne pouvez pas facilement assembler t2 et t3 dans une "collection".

EDIT: Dans l'ensemble, il vous semble (sauf si vous stockez plus de données que quelques chiffres et la taille) n'a pas besoin du tout d'une structure, et ne peut pas simplement utiliser un ancien vecteur simple .

typedef std::vector<int> TestStruct;


int t2_init[] = { 0, 1, 2 };
TestStruct t3(t3_init, t3_init + 3);

int t2_init[] = { 0, 1 };
TestStruct t2(t2_init, t2_init + 2);

int main() {}

Ce qui vous permettrait d'avoir à la fois t2 et t3 dans une collection ensemble. Malheureusement std::vector n'a pas (encore) de syntaxe d'initialisation de style tableau, j'ai donc utilisé un raccourci. Mais il est assez simple d'écrire une fonction pour remplir les vecteurs de manière agréable.

EDIT: OK, donc vous n'avez pas besoin d'une collection, mais vous devez la passer à une fonction, vous pouvez utiliser des modèles pour préserver la sécurité des types!

template <int N>
struct TestStruct {
    static const int length = N;
    int values[N];
};

TestStruct<3> t3 = {{0, 1, 2}};
TestStruct<2> t2 = {{0, 1}};

template <int N>
void func(const TestStruct<N> &ts) { /* you could make it non-const if you need it to modify the ts */
    for(int i = 0; i < N; ++i) { /* we could also use ts.length instead of N here */
        std::cout << ts.values[i] << std::endl;
    }
}

// this will work too...
template <class T>
void func2(const T &ts) { 
    for(int i = 0; i < ts.length; ++i) {
        std::cout << ts.values[i] << std::endl;
    }
}

int main() {
    func(t2);
    func(t3);
    func2(t2);
}
29
Evan Teran

GCC/Clang prennent en charge l'extension suivante

 
 typedef struct TestStruct 
 {
 int longueur; 
 int * valeurs; 
}; 
 
 TestStruct t = {3, (int []) {0, 1, 2}}; 
 TestStruct t2 = {4, (int []) {0, 1, 2, 3}}; 
 
3
zufuliu
struct TestStruct {
    int length;
    const int *values;
};

static const uint8_t TEST_STRUCT_VAL_1[] = {0, 1, 2};
const TestStruct t1 = {3, TEST_STRUCT_VAL_1};

static const uint8_t TEST_STRUCT_VAL_2[] = {0, 1, 2, 3};
const TestStruct t2 = {4, TEST_STRUCT_VAL_2};`

Dans mon cas, en programmation stm32 avec gcc/g ++, le tableau de valeurs est uniquement un stockage de données brutes, il s'agit donc de const statique et serait stocké en flash. J'utilise cette façon de stocker des modèles de polices pour l'affichage lcd.

en utilisant le modèle, vous enregistrez mais pas la taille.

1
aGuegu

VLA n'est pris en charge qu'en C99. C++ ne prend pas en charge cela. Depuis http://gcc.gnu.org/c99status.html , gcc prend désormais en charge VLA.

0
tristan