Tableau de longueur zéro
Je suis en train de refactoring quelques vieux code et ont trouvé quelques structures contenant zéro de tableaux de longueur (ci-dessous). Avertissements déprimé par pragma, bien sûr, mais je n'ai pas réussi à créer de "nouveaux" structures contenant de telles structures (erreur 2233). Tableau "byData" utilisé comme pointeur, mais pourquoi ne pas utiliser le pointeur de la place? ou un tableau de longueur 1? Et bien sûr, aucun commentaire n'a été ajouté à me faire apprécier le processus...
Les causes d'utiliser une telle chose? Tous les conseils dans la refactorisation de ceux-là?
struct someData
{
int nData;
BYTE byData[0];
}
NB C'est C++, Windows XP, VS 2003
- C'est le "struct hack", décrit à la question 2.6 de la comp.lang.c FAQ. Dennis Ritchie l'a appelé "injustifiée chumminess C avec la mise en œuvre". C99 a introduit une nouvelle fonctionnalité, le "flexible membre du groupe", afin de remplacer la structure hack. Même Microsoft compilateur, qui est connu pour son manque de support C99, prend en charge flexible des membres du groupe.
- Ne PAS ajouter de la
c
balise à cette question. Le C++ règles sont très différentes de la C règles. - L'on a accepté la réponse est pur le code en C, donc je suppose que votre montage est mauvais. c hack s'applique à la fois le c et le c++ de la même façon
- non, pas de la même façon. Ce code n'est pas valide en C++ à tous. Si elle est acceptée par le compilateur, c'est comme un Visual C++ extension (cette balise N'appartiennent).
Vous devez vous connecter pour publier un commentaire.
Oui, c'est un C-Hack.
Pour créer un tableau de n'importe quelle longueur:
Maintenant, vous avez un objet de someData avec un tableau d'une longueur spécifiée.
new[]
, ce cours sur le C++?BYTE
s, en supposant que ceux-ci sont définis pour être certainschar
variante.)Il y a, malheureusement, plusieurs raisons pourquoi vous pouvez déclarer une longueur de zéro tableau à la fin d'une structure. Il vous donne la possibilité d'avoir une longueur variable de la structure retourné à partir d'une API.
Raymond Chen a fait un excellent billet de blog sur le sujet. Je vous suggère de jeter un oeil à ce post car il contient probablement la réponse que vous voulez.
Note dans son poste, il traite avec des tableaux de taille 1 au lieu de 0.
C'est le cas en raison de la longueur zéro tableaux sont une entrée plus récente dans les normes.Son poste devrait toujours s'appliquer à votre problème.http://blogs.msdn.com/oldnewthing/archive/2004/08/26/220873.aspx
MODIFIER
Remarque: Même si Raymond du post dit 0 tableaux de longueur sont légaux en C99, ils sont en fait pas encore légal en C99. Au lieu d'un 0 longueur du tableau ici, vous devriez être en utilisant une longueur de 1 tableau
int arr[]
(depuis int protège contre les problèmes d'alignement), mais puisque nous sommes de retour le tableau, le mieux dans notre cas estvoid *arr[]
, ce qui est assez cryptographique.C'est un vieux C hack pour permettre une plus grande souplesse de la taille des tableaux.
En standard C99 ce n'est pas nécessaire car il prend en charge l'arr[] syntaxe.
Votre intution sur "pourquoi ne pas utiliser un tableau de taille 1" est sur place.
Le code est en train de faire le "C struct hack" de mal, parce que les déclarations de longueur zéro tableaux sont une violation de contrainte. Cela signifie qu'un compilateur peut rejeter votre hack droit au large de la chauve-souris au moment de la compilation avec un message de diagnostic qui s'arrête à la traduction.
Si nous voulons à commettre un hack, nous devons nous faufiler passé le compilateur.
La bonne façon de faire de la "C struct hack" (qui est compatible avec le C dialectes datant de 1989 en C ANSI, et probablement beaucoup plus tôt) est d'utiliser un bon tableau de taille 1:
En outre, au lieu de
sizeof struct someData
, la taille de la partie avant debyData
est calculée à l'aide de:D'allouer une
struct someData
avec de l'espace pour 42 octets dansbyData
, nous aurions alors utiliser:Noter que cette
offsetof
calcul est en fait le bon calcul, même dans le cas de la taille de la matrice étant zéro. Vous voyez,sizeof
l'ensemble de la structure peut inclure rembourrage. Par exemple, si nous avons quelque chose comme ceci:La taille de
struct hack
est très probablement rembourré pour l'alignement en raison de laul
membre. Siunsigned long
est de quatre octets de large, puis très probablementsizeof (struct hack)
est de 8, alors queoffsetof(struct hack, foo)
est presque certainement 5. Leoffsetof
méthode est le moyen d'obtenir la taille exacte de la partie précédente de la structure, juste avant le tableau.Alors que ce serait le moyen de refactoriser le code: le rendre conforme à la classique, ultra-portable struct hack.
Pourquoi ne pas utiliser un pointeur? Car un pointeur occupe de l'espace supplémentaire et doit être initialisé.
Il y a d'autres bonnes raisons de ne pas utiliser un pointeur, à savoir qu'un pointeur nécessite un espace d'adressage pour être utile. La structure hack est externalizeable: c'est-à-dire, il existe des situations dans lesquelles une telle disposition est conforme à la de stockage externes tels que les zones de fichiers, les paquets ou de la mémoire partagée, dans laquelle vous ne voulez pas des pointeurs, car ils ne sont pas significatives.
Il y a plusieurs années, j'ai utilisé la structure hack dans une mémoire partagée message passing interface entre le noyau et l'espace utilisateur. Je ne voulais pas les pointeurs, parce qu'ils auraient été significative seulement l'espace d'adressage du processus de génération d'un message. Le noyau d'une partie du logiciel a une vue à la mémoire à l'aide de sa propre cartographie à une adresse différente, et donc, tout était basé sur des calculs de décalage.
Il est intéressant de souligner l'OMI la meilleure façon de faire le calcul de la taille, qui est utilisé dans la Raymond Chen article lié ci-dessus.
Le décalage de la première entrée, à la fin de l'allocation, est aussi de la taille de ce qui était souhaité. IMO c'est un très élégante façon de faire le calcul de la taille. Il n'a pas d'importance ce que l'élément type de la variable tableau de taille est. Le offsetof (ou FIELD_OFFSET ou UFIELD_OFFSET dans Windows) est toujours écrit de la même manière. Pas de sizeof() expressions accidentellement en désordre.