135 votes

Que se passe-t-il si je définis un tableau de taille 0 en C/C++ ?

Par curiosité, que se passe-t-il si je définis un tableau de longueur nulle int array[0]; dans le code ? GCC ne se plaint pas du tout.

Exemple de programme

#include <stdio.h>

int main() {
    int arr[0];
    return 0;
}

Clarification

J'essaie en fait de comprendre si les tableaux de longueur nulle initialisés de cette manière, au lieu d'être pointés comme les tableaux de longueur variable dans les commentaires de Darhazer, sont optimisés ou non.

C'est parce que je dois publier du code dans la nature, et j'essaie donc de savoir si je dois gérer les cas où l'option SIZE est défini comme suit 0 , ce qui se produit dans certains codes avec un int array[SIZE];

J'ai été surpris de constater que le GCC ne se plaignait pas, ce qui m'a amené à poser ma question. D'après les réponses que j'ai reçues, je pense que l'absence d'avertissement est largement due à la prise en charge d'un ancien code qui n'a pas été mis à jour avec la nouvelle syntaxe [].

Parce que je m'interrogeais principalement sur l'erreur, je marque la réponse de Lundin comme correcte (celle de Nawaz était la première, mais elle n'était pas aussi complète) - les autres soulignaient son utilisation réelle pour les structures à queue, bien que pertinente, n'est pas exactement ce que je recherchais.

0 votes

On dirait que GCC ne se plaint pas du tout, et que vous devez l'initialiser. Qu'avez-vous besoin de savoir de plus, exactement, et pouvez-vous le découvrir en le faisant vous-même ?

0 votes

Ce sujet pourrait vous intéresser : stackoverflow.com/questions/295027/array-of-zero-length

52 votes

@AlexanderCorwin : Malheureusement, en C++, avec des comportements non définis, des extensions non standard et d'autres anomalies, essayer quelque chose soi-même n'est souvent pas une voie vers la connaissance.

94voto

Lundin Points 21616

Un tableau ne peut pas avoir une taille nulle.

ISO 9899:2011 6.7.6.2 :

Si l'expression est une expression constante, elle doit avoir une valeur supérieure à zéro.

Le texte ci-dessus s'applique aussi bien à un tableau simple (paragraphe 1). Pour un tableau de longueur variable (VLA), le comportement est indéfini si la valeur de l'expression est inférieure ou égale à zéro (paragraphe 5). Il s'agit d'un texte normatif dans la norme C. Un compilateur n'est pas autorisé à l'implémenter différemment.

gcc -std=c99 -pedantic donne un avertissement pour le cas où il n'y a pas de VLA.

2 votes

Où avez-vous trouvé cela ? C99 6.7.5.2 §5 : Si la taille est une expression qui n'est pas une expression constante entière [...] chaque fois qu'elle est évaluée, elle doit avoir une valeur supérieure à zéro.

34 votes

"la distinction entre "avertissements" et "erreurs" n'est pas reconnue dans la norme (elle ne mentionne que les "diagnostics"), et la seule situation où la compilation doit s'arrêter [c'est-à-dire la différence réelle entre l'avertissement et l'erreur] est celle où l'on rencontre une erreur. #error directive.

12 votes

Pour information, en règle générale, les normes (C ou C++) indiquent seulement ce que les compilateurs doivent permettre mais pas ce qu'ils doivent désavouer . Dans certains cas, ils indiquent que le compilateur doit émettre un "diagnostic", mais c'est à peu près tout ce qu'ils ont à dire. Le reste est laissé à l'appréciation du vendeur du compilateur. EDIT : Ce que Random832 a dit aussi.

91voto

Matthieu M. Points 101624

Selon la norme, cela n'est pas autorisé.

Cependant, les compilateurs C ont l'habitude de traiter ces déclarations comme des _membre d'un tableau flexible ( FAM )_ déclaration :

C99 6.7.2.1, §16 : Dans un cas particulier, le dernier élément d'une structure comportant plusieurs membres nommés peut avoir un type de tableau incomplet ; il s'agit alors d'un membre de tableau flexible.

La syntaxe standard d'un FAM est la suivante :

struct Array {
  size_t size;
  int content[];
};

L'idée est de l'allouer de cette manière :

void foo(size_t x) {
  Array* array = malloc(sizeof(size_t) + x * sizeof(int));

  array->size = x;
  for (size_t i = 0; i != x; ++i) {
    array->content[i] = 0;
  }
}

Vous pouvez également l'utiliser de manière statique (extension gcc) :

Array a = { 3, { 1, 2, 3 } };

Il est également connu sous le nom de Structures de la queue (ce terme est antérieur à la publication de la norme C99) ou struct hack (merci à Joe Wreschnig de l'avoir signalé).

Toutefois, cette syntaxe n'a été normalisée (et ses effets garantis) que récemment, en C99. Auparavant, une taille constante était nécessaire.

  • 1 était la solution portable, bien qu'elle soit assez étrange.
  • 0 était plus efficace pour indiquer l'intention, mais n'était pas légale en ce qui concerne la norme et était supportée comme extension par certains compilateurs (y compris gcc).

La pratique du rembourrage de la queue repose toutefois sur le fait que l'espace de stockage est disponible (prudent). malloc ), il en est de même pour le ne convient pas à l'utilisation de la pile en général.

0 votes

@Lundin : Je n'ai pas vu de VLA ici, toutes les tailles sont connues au moment de la compilation. Les réseau flexible Le terme vient de gcc.gnu.org/onlinedocs/gcc-4.1.2/gcc/Zero-Length.html et se qualifie int content[]; d'après ce que j'ai compris. Comme je ne suis pas très au fait des termes de l'art... pourriez-vous me confirmer si mon raisonnement semble correct ?

0 votes

@MatthieuM. : C99 6.7.2.1, §16 : Dans un cas particulier, le dernier élément d'une structure comportant plusieurs membres nommés peut avoir un type de tableau incomplet ; il s'agit alors d'un membre de tableau flexible.

0 votes

Cet idiome est également connu sous le nom de "struct hack" et j'ai rencontré plus de personnes familières avec ce nom que "tail-padded structure" (jamais entendu auparavant, sauf peut-être comme une référence générique au remplissage d'une structure pour une future compatibilité ABI) ou "flexible array member" que j'ai entendu pour la première fois en C99.

58voto

Nawaz Points 148870

En C et C++ standard, un tableau de taille nulle est no autorisé

Si vous utilisez GCC, compilez-le avec -pedantic option. Elle donnera avertissement en disant :

zero.c:3:6: warning: ISO C forbids zero-size array 'a' [-pedantic]

Dans le cas de C++, il donne un avertissement similaire.

9 votes

Dans Visual C++ 2010 : error C2466: cannot allocate an array of constant size 0

4 votes

-Werror transforme simplement tous les avertissements en erreurs, ce qui ne corrige pas le comportement incorrect du compilateur GCC.

0 votes

C++ Builder 2009 donne également une erreur : [BCC32 Error] test.c(3): E2021 Array must have at least one element

28voto

James Kanze Points 96599

C'est totalement illégal, et l'a toujours été, mais de nombreux compilateurs négligent de signaler l'erreur. Je ne vois pas très bien pourquoi vous voulez faire cela. La seule utilisation que je connaisse est de déclencher une erreur de compilation à partir d'un booléen :

char someCondition[ condition ];

Si condition est faux, j'obtiens une erreur de compilation. Parce que les compilateurs les compilateurs le permettent, j'ai pris l'habitude d'utiliser :

char someCondition[ 2 * condition - 1 ];

Cela donne une taille de 1 ou de -1, et je n'ai jamais trouvé de compilateur qui accepterait une taille de -1.

0 votes

Il s'agit d'une utilisation intéressante.

10 votes

Il s'agit d'une astuce courante en métaprogrammation, je crois. Je ne serais pas surpris que les implémentations de STATIC_ASSERT l'a utilisé.

0 votes

Pourquoi ne pas se contenter de.. : #if condition \n #error whatever \n #endif

9voto

xanatos Points 30513

J'ajouterai qu'il existe un page entière de la documentation en ligne de gcc sur cet argument.

Quelques citations :

Les tableaux de longueur nulle sont autorisés dans GNU C.

Dans la norme ISO C90, il faudrait donner au contenu une longueur de 1

y

Les versions de GCC antérieures à la 3.0 permettaient d'initialiser statiquement les tableaux de longueur nulle, comme s'il s'agissait de tableaux flexibles. En plus des cas utiles, cela permettait également des initialisations dans des situations qui auraient corrompu des données ultérieures

pour que vous puissiez

int arr[0] = { 1 };

et boum :-)

0 votes

Puis-je faire comme int a[0] entonces a[0] = 1 a[1] = 2 ? ?

2 votes

@SurajJain Si vous voulez écraser votre pile :-) C ne vérifie pas l'index par rapport à la taille du tableau que vous écrivez, donc vous pouvez a[100000] = 5 mais si vous avez de la chance, vous ferez simplement planter votre application, si vous avez de la chance :-)

0 votes

Int a[0] ; signifie un tableau variable (tableau de taille zéro), comment puis-je l'assigner ?

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