web-dev-qa-db-fra.com

Initialisation C struct à l'aide d'étiquettes. Ça marche, mais comment?

Hier, j'ai trouvé un code d'initialisation struct qui m'a jeté pour une boucle. Voici un exemple:

typedef struct { int first; int second; } TEST_STRUCT;
void testFunc() {
    TEST_STRUCT test = {
        second: 2,
        first:  1
    };
    printf("test.first=%d test.second=%d\n", test.first, test.second);
}

Étonnamment (pour moi), voici la sortie:

-> testFunc
test.first=1 test.second=2

Comme vous pouvez le voir, la structure est correctement initialisée. Je ne savais pas que des déclarations étiquetées pouvaient être utilisées comme ça. J'ai vu plusieurs autres façons de faire l'initialisation de la structure, mais je n'ai trouvé aucun exemple de ce type d'initialisation de la structure sur aucune des FAQ C en ligne. Quelqu'un sait-il comment/pourquoi cela fonctionne?

41
Andrew Cottrell

Voici la section du manuel gcc qui explique la syntaxe des initialiseurs désignés pour les structures et les tableaux:

Dans un initialiseur de structure, spécifiez le nom d'un champ à initialiser avec '. Fieldname = ' avant la valeur de l'élément. Par exemple, étant donné la structure suivante,

 struct point { int x, y; };

l'initialisation suivante

 struct point p = { .y = yvalue, .x = xvalue }; 

est équivalent à

 struct point p = { xvalue, yvalue }; 

Une autre syntaxe qui a la même signification, obsolète depuis GCC 2.5, est ' nom de champ: ', comme indiqué ici:

 struct point p = { y: yvalue, x: xvalue };

La page pertinente peut être trouvée ici .

Votre compilateur doit avoir une documentation similaire.

41
sigjuice

Ce ne sont ni des étiquettes ni des champs de bits.

Il s'agit d'une syntaxe pour initialiser les membres de structure remontant aux jours avant C99. Il n'est pas normalisé mais disponible par ex. gcc.

typedef struct { int y; int x; } POINT;
POINT p = { x: 1, y: 17 };

En C99, la syntaxe pour initialiser des membres de structure spécifiques a été introduite pour la première fois dans un standard, mais elle a un aspect un peu différent:

typedef struct { int y; int x; } POINT;
POINT p = { .x = 1, .y = 17 };
33
ndim

Oui, comme indiqué ci-dessus, ce sont des initialiseurs désignés, qui sont du C standard, bien que vous deviez utiliser des points plutôt que des deux-points. Et comme vous le constatez, la plupart des livres là-bas sont toujours coincés quelque part vers 1984 dans leur syntaxe et ne les mentionnent pas. Plus de faits amusants:

- Lorsque vous utilisez des initialiseurs désignés, tout ce qui n'est pas spécifié est initialisé à zéro. Cela aide avec des structures exceptionnellement grandes, par exemple:

typedef struct {
   double a, b, c, d, e;
   char label[100];
} too_many_type;

too_many_type tm = {.a = 1, .e = 2, .b=1.5};
assert(tm.a + tm.b + tm.c + tm.d + tm.e == 4.5);
assert(!strlen(label));

- Vous pouvez également utiliser le formulaire littéral composé pour utiliser ce formulaire sur une ligne de non-initialisation, par exemple:

too_many_type tm2;
tm2 = (too_many_type) {.a = 3, .e=6};

Ce sont de très bonnes fonctionnalités, et sont prises en charge par tous les compilateurs C auxquels je peux penser, étant donné que c'est la norme. C'est dommage qu'ils ne soient pas si connus.

12
bk.

Ce n'est pas vraiment des "instructions étiquetées", mais un moyen de donner des valeurs initiales aux champs nommés dans la structure.

Gcc donne un avertissement sur "l'utilisation obsolète de l'initialiseur désigné avec ':'", et en C99 vous devriez plutôt écrire:

    TEST_STRUCT test = {
        .second = 2,
        .first =  1
    };
5

Cette syntaxe n'est pas définie par la norme C. Section 6.7.8 Initialization dit

         designation:
                designator-list =
         designator-list:
                designator
                designator-list designator
         designator:
                [ constant-expression ]
                . identifier

Si votre compilateur accepte une désignation avec deux points sans message de diagnostic, cela signifie que votre compilateur n'est pas (ou n'est pas configuré) conforme aux normes.

3
pmg