Question

Dans notre code, nous avions quelque chose comme ceci:

   *(controller->bigstruct) = ( struct bigstruct ){ 0 };

Cela fonctionnait très bien, puis nous avons mis à niveau les versions de GCC et avons soudainement commencé à voir des débordements de pile. En regardant l’assemblage, l’ancien code GCC (2.x) faisait essentiellement ceci:

memset(controller->bigstruct, 0, sizeof(struct bigstruct));

Le nouveau GCC (3.4.x) était en train de le faire

   struct bigstruct temp = { 0 };
   controller->bigstruct = temp;

Après avoir examiné la spécification C99, je pouvais voir pourquoi; C99 requiert essentiellement que des structures anonymes existent sur la pile. C'est un bon concept, mais cette structure faisait 4 Mo de taille et ne devait exister que sur le tas!

Nous avons créé notre propre fonction "initialiser" qui définit explicitement les membres, mais c'est moche et un casse-tête de maintenance. Je ne considère pas memset comme une solution appropriée, car je ne peux pas savoir qu'une valeur de bit égale à 0 est une valeur zéro appropriée pour le type (choix médiocre, je sais, mais vous y êtes; cela ne me dérange pas le compilateur le fait, car il peut savoir)

Quel est le "correct" ou, du moins, le meilleur moyen d'initialiser une grande structure comme celle-ci?

Pour clarifier davantage pourquoi je pense que memset n’est pas une solution: les règles d’initialisation des membres non explicitement initialisées sont identiques à celles de l’initialisation statique et sont les suivantes:    - S'il est de type pointeur, il est initialisé à un pointeur nul;    - s'il est de type arithmétique, il est initialisé à zéro (positif ou non signé);    ...

'memset' mettra la mémoire à bit-pattern zéro, ce qui n'est pas nécessairement la même chose Imaginez un système qui n'utilise pas de nombres à virgule flottante IEEE. Inhabituel, mais pris en charge par C. La représentation de 0.0 ne doit pas nécessairement signifier "bits nuls tous", cela pourrait être pratique pour le processeur.

Était-ce utile?

La solution

memset est la voie à suivre. Vous n'avez pas beaucoup d'alternatives.

Faites quelque chose comme:

#define InitStruct(var, type) type var; memset(&var, 0, sizeof(type))

Pour qu'il ne vous reste plus qu'à:

InitStruct(st, BigStruct);

Et utilisez ensuite st comme d'habitude ...

Je ne comprends pas comment " 0 " n'est pas valide " 0 " tapez pour un struct. La seule façon de "masser en masse" une structure doit mettre toute sa mémoire à une valeur; sinon, vous devrez créer une logique supplémentaire pour lui dire d'utiliser un modèle de bits spécifique par membre. Le meilleur " générique " modèle de bit à utiliser est 0.

En outre, c’est la même logique que celle que vous avez utilisée pour faire

.
*(controller->bigstruct) = *( struct bigstruct ){ 0 };

Par conséquent, je ne comprends pas votre réticence à l'utiliser:)

Le premier commentaire de ce billet m'a incité à faire des recherches avant que je l'appelle idiot et que je trouve ceci:

http://www.lysator.liu.se/ c / c-faq / c-1.html

Très intéressant; si je pouvais voter un commentaire, je le ferais:)

Cela dit, votre seule option si vous souhaitez cibler des architectures archaïques avec des valeurs nulles non nulles reste l'initialisation manuelle de certains membres.

Merci Thomas Padron-McCarthy! J'ai appris quelque chose de nouveau aujourd'hui:)

Autres conseils

Si vous ne souhaitez pas utiliser memset, vous pouvez toujours déclarer une copie statique de votre structure et utiliser memcpy, ce qui donnera des performances similaires. Cela ajoutera 4 Mo à votre programme mais sera probablement mieux que de définir des éléments individuels.

Cela dit, si GCC utilisait memset et qu’il était suffisamment bon auparavant, je dirais que c’est assez bon maintenant.

Comme d'autres l'ont déjà dit, memset est la voie à suivre. Cependant, ne n'utilisez pas memset sur les objets C ++, en particulier ceux utilisant des méthodes virtuelles. Le sizeof (foo) inclura le tableau des pointeurs de fonction virtuels, et faire un memset sur ce qui causera de graves problèmes.

Si memset ne résout pas le problème par lui-même, créez simplement un memset et puis initialisez tous les membres qui doivent être non nuls (c'est-à-dire vos valeurs à virgule flottante non-IEEE).

La fonction d’initialisation privée n’est pas moche mais plutôt un bon moyen d’initialisation d’objets (structs). Je suppose que votre structure n’est pas composée de 4 Mo de pointeurs. Je suppose donc que la solution devrait être la suivante:

void init_big_struct(struct bigstruct *s)  
{  
    memset(s, 0, sizeof(struct bigstruct));  
    s->some_pointer = NULL; // Multiply this as needed  
}

D’autre part, notre code s’exécute sur plus de 20 systèmes d’exploitation intégrés et sur un grand nombre de matériels différents, ne rencontrant jamais de problème avec un simple memset de la structure.

hmm - tout d’abord, créer une fonction init et définir explicitement chaque membre est la bonne chose - c’est la façon dont les constructeurs fonctionnent dans les langages OO.

et deuxièmement - quelqu'un connaît-il un matériel implémentant des nombres à virgule flottante non IEEE? - peut-être Commodore 64 ou somethig; -)

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top