web-dev-qa-db-fra.com

Comment initialiser une structure conformément aux normes du langage de programmation C

Je veux initialiser un élément struct, scindé en déclaration et initialisation. C'est ce que j'ai

typedef struct MY_TYPE {
  bool flag;
  short int value;
  double stuff;
} MY_TYPE;

void function(void) {
  MY_TYPE a;
  ...
  a = { true, 15, 0.123 }
}

Est-ce la manière de déclarer et d'initialiser une variable locale de MY_TYPE conformément aux normes de langage de programmation C (C89, C90, C99, C11, etc.)? Ou y a-t-il quelque chose de mieux ou au moins de travail?

Mise à jour J'ai fini par avoir un élément d'initialisation statique dans lequel je règle chaque sous-élément en fonction de mes besoins.

414
cringe

Dans (ANSI) C99, vous pouvez utiliser un initialiseur désigné pour initialiser une structure:

MY_TYPE a = { .flag = true, .value = 123, .stuff = 0.456 };

Edit: les autres membres sont initialisés à zéro: "Les membres de champ omis sont implicitement initialisés de la même manière que les objets ayant une durée de stockage statique." ( https://gcc.gnu.org/onlinedocs/gcc/Designated-Inits.html )

671
philant

Vous pouvez le faire avec un composé littéral . Selon cette page, cela fonctionne en C99 (qui compte aussi comme ANSI C ).

MY_TYPE a;

a = (MY_TYPE) { .flag = true, .value = 123, .stuff = 0.456 };
...
a = (MY_TYPE) { .value = 234, .stuff = 1.234, .flag = false };

Les désignations dans les initialiseurs sont facultatives; vous pouvez aussi écrire:

a = (MY_TYPE) { true,  123, 0.456 };
...
a = (MY_TYPE) { false, 234, 1.234 };
180
CesarB

Je vois que vous avez déjà reçu une réponse à propos de la norme ANSI C 99, alors je vais vous parler de la norme ANSI C 89. La norme ANSI C 89 vous permet d’initialiser une structure de la manière suivante:

typedef struct Item {
    int a;
    float b;
    char* name;
} Item;

int main(void) {
    Item item = { 5, 2.2, "George" };
    return 0;
}

Une chose importante à retenir, au moment où vous initialisez un seul objet/variable dans la structure, toutes ses autres variables seront initialisées à la valeur par défaut.

Si vous n'initialisez pas les valeurs de votre structure, toutes les variables contiendront des "valeurs parasites".

Bonne chance!

85
Ron Nuni

a = (MYTYPE){ true, 15, 0.123 };

ferait bien en C99

35
qrdl

Vous l'avez presque ...

MY_TYPE a = { true,15,0.123 };

Rapide recherche sur 'struct initialize c'me montre ceci

18
Kieveli

comme Ron Nuni a dit:

typedef struct Item {
    int a;
    float b;
    char* name;
} Item;

int main(void) {
    Item item = {5, 2.2, "George"};
    return 0;
}

Une chose importante à retenir: au moment où vous initialisez un seul objet/variable dans la structure, toutes ses autres variables seront initialisées à la valeur par défaut.

Si vous n'initialisez pas les valeurs dans votre structure (c'est-à-dire si vous venez de déclarer cette variable), tout variable.members contiendra des "valeurs parasites", niquement si la déclaration est locale!

Si la déclaration est globale ou statique (comme dans ce cas), tout non initialisé variable.members sera automatiquement initialisé sur:

  • 0 pour les entiers et les virgules flottantes
  • '\0' pour char (bien sûr, cela est identique à 0 et char est un type entier)
  • NULL pour les pointeurs.
13
r_goyal

La norme de langage de programmation C ISO/IEC 9899: 1999 (communément appelée C99) autorise l’utilisation d’un initialiseur pour initialiser les membres d'une structure ou d'un syndicat comme suit:

MY_TYPE a = { .stuff = 0.456, .flag = true, .value = 123 };

Il est défini dans paragraph 7, section 6.7.8 Initialization de la norme ISO/IEC 9899: 1999 comme suit:

Si un désignateur a la forme
. identifiant
alors l'objet courant (défini ci-dessous) doit avoir une structure ou un type d'union et l'identificateur doit être le nom d'un membre de ce type.

Notez que paragraph 9 de la même section indique que:

Sauf indication contraire explicite, aux fins du présent sous-paragraphe, les membres non nommés d’objets de type structure et union ne participent pas à l’initialisation. Les membres non nommés des objets de structure ont une valeur indéterminée même après l'initialisation.

Dans GNU GCC, les membres omis sont initialisés avec une valeur de type zéro ou de type zéro. Comme indiqué dans la section 6.27 Initializers désignés de GNU GCC documentation:

Les membres de champ omis sont implicitement initialisés de la même manière que les objets ayant une durée de stockage statique.

Le compilateur Microsoft Visual C++ doit prendre en charge les initialiseurs désignés à partir de la version 2013, conformément au message officiel du blog C++ Conformance Roadmap . Le paragraphe Initializing unions and structs of Initializers de l'article dans MSDN, la documentation de Visual Studio suggère que les membres non nommés sont initialisés avec des valeurs appropriées analogues à zéro, de la même manière que GNU GCC.

La norme ISO/IEC 9899: 2011 (connue sous le nom de C11) qui avait remplacé ISO/IEC 9899: 1999 conserve les initialiseurs désignés dans la section 6.7.9 Initialization. Il conserve également paragraph 9 inchangé.

La nouvelle norme ISO/IEC 9899: 2018 (connue sous le nom de C18) remplaçant ISO/IEC 9899: 2011 conserve les initialiseurs désignés dans la section 6.7.9 Initialization. Il conserve également paragraph 9 inchangé.

13
PF4Public
void function(void) {
  MY_TYPE a;
  a.flag = true;
  a.value = 15;
  a.stuff = 0.123;
}
4
robert

J'ai trouvé un autre moyen d'initialiser les structures.

La structure:

typedef struct test {
    int num;
    char* str;
} test;

Initialisation:

test tt = {
    num: 42,
    str: "Nice"
};

Selon la documentation de GCC, cette syntaxe est obsolète depuis GCC 2.5 .

2
MichaelWang

Si MS n'a pas été mis à jour en C99, MY_TYPE a = {true, 15,0.123};

2
eddyq

Je n'aimais aucune de ces réponses alors j'ai fait les miennes. Je ne sais pas s'il s'agit d'ANSI C ou non, il s'agit simplement de GCC 4.2.1 dans son mode par défaut. Je ne me souviens jamais de la mise entre parenthèses. Je commence donc par un sous-ensemble de mes données et je me bats avec les messages d'erreur du compilateur jusqu'à ce que cela se ferme. La lisibilité est ma première priorité.

    // in a header:
    typedef unsigned char uchar;

    struct fields {
      uchar num;
      uchar lbl[35];
    };

    // in an actual c file (I have 2 in this case)
    struct fields labels[] = {
      {0,"Package"},
      {1,"Version"},
      {2,"Apport"},
      {3,"Architecture"},
      {4,"Bugs"},
      {5,"Description-md5"},
      {6,"Essential"},
      {7,"Filename"},
      {8,"Ghc-Package"},
      {9,"Gstreamer-Version"},
      {10,"Homepage"},
      {11,"Installed-Size"},
      {12,"MD5sum"},
      {13,"Maintainer"},
      {14,"Modaliases"},
      {15,"Multi-Arch"},
      {16,"Npp-Description"},
      {17,"Npp-File"},
      {18,"Npp-Name"},
      {19,"Origin"}
    };

Les données peuvent commencer à l’état de vie en tant que fichier délimité par des tabulations que vous recherchez-remplacez pour les transformer en quelque chose de différent. Oui, c'est du matériel Debian. Donc une paire extérieure de {} (indiquant le tableau), puis une autre paire pour chaque structure à l'intérieur. Avec des virgules entre. Il n'est pas absolument nécessaire de placer des éléments dans un en-tête, mais j'ai environ 50 éléments dans ma structure. Je veux donc les placer dans un fichier séparé, afin d'éviter que mon code ne soit gâché et qu'il soit plus facile de le remplacer.

1
Alan Corey

J'ai lu le documentation de Microsoft Visual Studio 2015 sur l'initialisation des types d'agrégats , toutes les formes d'initialisation avec {...} y sont expliquées, mais l'initialisation avec un point, nommé "désignateur", n'y est pas mentionnée. Cela ne marche pas aussi.

Le chapitre 6.7.8 de la norme C99 explique la possibilité de désigner des indicatifs, mais à mon avis, cela n’est pas vraiment clair pour les structures complexes. Le standard C99 en pdf .

Dans mon esprit, il peut être préférable de

  1. Utilisez l'initialisation = {0};- pour toutes les données statiques. C'est moins d'effort pour le code machine.
  2. Utiliser des macros pour l'initialisation, par exemple

    typedef MyStruct_t{ int x, int a, int b; } MyStruct; define INIT_MyStruct(A,B) { 0, A, B}

La macro peut être adaptée, sa liste d'arguments peut être indépendante du contenu struct modifié. Il convient que moins d'éléments soient initialisés. C'est également approprié pour la structure imbriquée. 3. Un formulaire simple est: Initialiser dans un sous-programme:

void init_MyStruct(MyStruct* thiz, int a, int b) {
  thiz->a = a; thiz->b = b; }

Cette routine ressemble à ObjectOriented in C. Utilisez thizet non thispour le compiler avec C++ également!

MyStruct data = {0}; //all is zero!
init_MyStruct(&data, 3, 456);
0
Hartmut Schorrig

La structure en C peut être déclarée et initialisée comme ceci:

typedef struct book
{
    char title[10];
    char author[10];
    float price;
} book;

int main() {
    book b1={"DS", "Ajay", 250.0};

    printf("%s \t %s \t %f", b1.title, b1.author, b1.price);

    return 0;
}
0
Ajay Parashar