52 votes

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

34voto

Loki Astari Points 116129

Oui c'est un C-Hack.
Pour créer un tableau de n'importe quelle longueur:

 struct someData* mallocSomeData(int size)
{
    struct someData*  result = (struct someData*)malloc(sizeof(struct someData) + size * sizeof(BYTE));
    if (result)
    {    result->nData = size;
    }
    return result;
}
 

Maintenant, vous avez un objet de someData avec un tableau d'une longueur spécifiée.

25voto

JaredPar Points 333733

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.

Remarque 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 emploi devrait encore 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

22voto

arul Points 10719

C'est un vieux hack en C pour permettre des tableaux de tailles flexibles.

En standard C99, ce n'est pas nécessaire car il supporte la syntaxe arr [].

9voto

Kaz Points 18072

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:

struct someData
{
   int nData;
   unsigned char byData[1];
}

En outre, au lieu de sizeof struct someData, la taille de la partie avant de l' byData est calculé à l'aide de:

offsetof(struct someData, byData);

Pour allouer un struct someData avec de l'espace pour 42 octets en byData, nous aurions alors utiliser:

struct someData *psd = (struct someData *) malloc(offsetof(struct someData, byData) + 42);

Notez que ce 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 de l'ensemble de la structure peut inclure rembourrage. Par exemple, si nous avons quelque chose comme ceci:

struct hack {
  unsigned long ul;
  char c;
  char foo[0]; /* assuming our compiler accepts this nonsense */
};

La taille de l' struct hack est très probablement rembourré pour l'alignement en raison de l' ul membre. Si unsigned long est de quatre octets de large, puis, éventuellement, sizeof (struct hack) 8, alors que offsetof(struct hack, foo) est presque certainement 5. L' offsetof 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.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X