web-dev-qa-db-fra.com

C et C ++: Initialisation partielle de la structure automatique

Par exemple, si somestruct a trois membres entiers, j'ai toujours pensé que c'était bien de le faire en fonction C (ou C++):

somestruct s = {123,};

Le premier membre serait initialisé à 123 et les deux derniers seraient initialisés à 0. Je fais souvent la même chose avec les tableaux automatiques, en écrivant int arr[100] = {0,}; pour que tous les entiers d'un tableau soient initialisés à zéro.


Récemment, j'ai lu dans le GNU C Reference Manual que:

Si vous n'initialisez pas une variable de structure, l'effet dépend de son stockage statique (voir Spécificateurs de classe de stockage) ou non. Si c'est le cas, les membres avec des types intégraux sont initialisés avec 0 et les membres du pointeur sont initialisés à NULL; sinon, la valeur des membres de la structure est indéterminée.


Quelqu'un peut-il me dire ce que disent les normes C et C++ concernant la structure automatique partielle et l'initialisation automatique des tableaux? Je fais le code ci-dessus dans Visual Studio sans problème, mais je veux être compatible avec gcc/g ++, et peut-être aussi d'autres compilateurs. Merci

65
loop

La documentation gcc liée ne parle pas de Initialisation partielle elle parle juste de (Complète) Initialisation ou Pas d'initialisation.

Qu'est-ce qu'une initialisation partielle?

Les normes ne définissent pas l'initialisation partielle des objets, soit l'initialisation complète, soit la non-initialisation. L'initialisation partielle est une terminologie non standard qui fait généralement référence à une situation dans laquelle vous fournissez des initialiseurs mais pas tous, c'est-à-dire: moins d'initialiseurs que la taille du tableau ou le nombre d'éléments de structure en cours d'initialisation.

Exemple:

int array[10] = {1,2};                    //Case 1:Partial Initialization

Qu'est-ce que l'initialisation (complète) ou pas d'initialisation?

L'initialisation signifie fournir une valeur initiale à la variable en cours de création en même temps qu'elle est en cours de création. c'est-à-dire: dans la même instruction de code.

Exemple:

int array[10] = {0,1,2,3,4,5,6,7,8,9};    //Case 2:Complete Initialization
int array[10];                            //Case 3:No Initialization

Le paragraphe cité décrit le comportement de Case 3.

Les règles concernant l'initialisation partielle (Case 1) Sont bien définies par la norme et ces règles ne dépendent pas du type de stockage de la variable en cours d'initialisation.
AFAIK, Tous les compilateurs traditionnels ont 100% de conformité à ces règles.


Quelqu'un peut-il me dire ce que disent les normes C et C++ concernant la structure automatique partielle et l'initialisation automatique des tableaux?

Les normes C et C++ garantissent que même si un tableau d'entiers se trouve sur le stockage automatique et s'il y a moins d'initialiseurs dans une liste entre accolades, les éléments non initialisés doit être initialisés à 0 .

Norme C99 6.7.8.21

S'il y a moins d'initialiseurs dans une liste entre accolades qu'il n'y a d'éléments ou de membres d'un agrégat, ou moins de caractères dans un littéral de chaîne utilisé pour initialiser un tableau de taille connue qu'il n'y a d'éléments dans le tableau, le reste de l'agrégat doit être initialisé implicitement comme les objets qui ont une durée de stockage statique.


En C++, les règles sont énoncées avec une petite différence.

Agrégats C++ 03 Standard 8.5.1
Para 7:

S'il y a moins d'initialiseurs dans la liste qu'il n'y a de membres dans l'agrégat, alors chaque membre non explicitement initialisé sera valeur-initialisée (8.5). [Exemple:

 struct S { int a; char* b; int c; };
 S ss = { 1, "asdf" };

initialise ss.a avec 1, ss.b avec "asdf" et ss.c avec la valeur d'une expression de la forme int(), c'est-à-dire 0. ]

Alors que l'initialisation de la valeur est définie dans,
C++ 03 8.5 Initialiseurs
Para 5:

To value-initialize un objet de type T signifie:
- si T est un type de classe (article 9) avec un constructeur déclaré par l'utilisateur (12.1), alors le constructeur par défaut pour T est appelé (et l'initialisation est incorrecte si T n'a pas de constructeur par défaut accessible) ;
- si T est un type de classe non-union sans constructeur déclaré par l'utilisateur, alors chaque membre de données non statique et composant de classe de base de T est initialisé en valeur;
- si T est un type de tableau, alors chaque élément est initialisé en valeur;
- sinon, l'objet est initialisé à zéro

92
Alok Save

En C, les objets sont jamais partiellement initialisés - si une partie d'entre eux est initialisée, l'objet entier (et tous les sous-objets récursivement) sont initialisés. Si aucun initialiseur explicite n'est fourni, les éléments sont initialisés à "zéro du type approprié".

La citation dans votre question fait référence au moment où l'initialiseur pour l'objet entier est complètement omis, pas quand un sous-objet n'a pas d'initialiseur. Par exemple, en supposant que arr a une durée de stockage automatique, alors ceci:

int arr[100] = { 123 };

initialise arr[0] à 123 et tous les autres éléments de arr à 0. Attendu que:

int arr[100];

laisse chaque élément de arr non initialisé. C'est dans ce dernier cas que la citation fait référence.

16
caf

les dernières versions de gcc permettent également d'initialiser "partiellement" et de zeromem en même temps:

typedef struct{
  int a,b,c;
}T;

T s = {0, .b=5};

les membres struct auront maintenant ces valeurs: a=0, b=5, c=0

je n'ai aucune information sur si d'autres compilateurs le permettent ou non: p

5
rocket441

Si la variable est globale et statique, elle alloue dans la zone globale des binaires qui est initialisée à zéro. Si la variable est locale, elle alloue dans la pile, le compilateur n'initialise pas la mémoire dans la pile (une version de débogage peut s'initialiser, mais la version finale ne le fait jamais)

Si la variable est allouée dans Heap, le compilateur ne l'initialise pas non plus.

0
RolandXu
// You can use something like this:
typedef struct {

    ...;

    ...;

} somestruct;

// Declaration of struct
somestruct st;

// Initialising with 0. It does not depend on the size of the
// structure and the number of elements in it.
// memset() initialisation doesn't care if struct is static or dynamic.
// but don't forget to use st instead &st to dynamic.
memset(&st, 0, sizeof(somestruct));
0
Dennis V.R.