web-dev-qa-db-fra.com

Comment cette structure peut-elle avoir sizeof == 0?

Il y a un ancien post demandant une construction pour laquelle sizeof renverrait 0. Certains utilisateurs ayant une réputation élevée ont obtenu des scores élevés, affirmant que, selon la norme, aucun type ou variable ne peut avoir une taille de 0. Et je suis tout à fait d’accord avec cela.

Cependant il y a cette nouvelle réponse qui présente cette solution:

struct ZeroMemory {
    int *a[0];
};

J'étais sur le point de voter et de commenter, mais le temps passé ici m'a appris à vérifier même les points sur lesquels je suis à 100% sûr. Donc ... à ma grande surprise, gcc et clang affichent les mêmes résultats: sizeof(ZeroMemory) == 0. Encore plus, la taille d'une variable est 0:

ZeroMemory z{};
static_assert(sizeof(z) == 0); // Awkward...

Whaaaat ...?

lien Godbolt

Comment est-ce possible?

78
bolov

Avant que C ne soit normalisé, de nombreux compilateurs n’auraient eu aucune difficulté à gérer les types de taille nulle tant que le code n’a jamais tenté de soustraire un pointeur à un type de taille zéro. De tels types sont utiles et leur support est plus facile et moins coûteux que de les interdire. Cependant, d'autres compilateurs ont décidé d'interdire de tels types, et certains codes à assertion statique ont pu s'appuyer sur le fait qu'ils craqueraient si le code essayait de créer un tableau de taille zéro. Les auteurs de la norme ont été confrontés à un choix:

  1. Autoriser les compilateurs à accepter en silence les déclarations de tableau de taille zéro, même dans les cas où le but de telles déclarations est de déclencher une compilation de diagnostic et d'abandon, et obliger tous les compilateurs à accepter de telles déclarations (bien que pas nécessairement en silence) comme produisant des objets de taille zéro .

  2. Autorisez les compilateurs à accepter en silence les déclarations de tableau de taille zéro, même dans les cas où le but de telles déclarations est de déclencher une compilation de diagnostics et d'abandons, et autorisez les compilateurs qui rencontrent de telles déclarations à annuler la compilation ou à la poursuivre à leur guise.

  3. Exiger que les implémentations émettent un diagnostic si le code déclare un tableau de taille zéro, puis autoriser les implémentations soit à abandonner la compilation, soit à le poursuivre (avec la sémantique qui leur convient le mieux).

Les auteurs de la norme ont opté pour # 3. Par conséquent, les déclarations de tableau de taille zéro sont considérées comme une "extension" standard, même si ces constructions ont été largement prises en charge avant que la norme ne les interdise.

La norme C++ permet l'existence d'objets vides, mais dans le but de permettre aux adresses d'objets vides d'être utilisables en tant que jetons, elle impose une taille minimale de 1. Pour un objet sans membres, sa taille est 0 violerait donc la norme. Toutefois, si un objet contient des membres de taille zéro, la norme C++ n'impose aucune condition en ce qui concerne son traitement, mis à part le fait qu'un programme contenant une telle déclaration doit déclencher un diagnostic. Étant donné que la plupart des codes utilisant de telles déclarations prévoient que les objets résultants ont une taille égale à zéro, le comportement le plus utile pour les compilateurs recevant un tel code consiste à les traiter de cette manière.

50
supercat

Comme indiqué par Jarod42 , les tableaux de taille zéro ne sont pas des standards C++, mais des extensions GCC et Clang.

Ajouter -pedantic _ produit cet avertissement:

5 : <source>:5:12: warning: zero size arrays are an extension [-Wzero-length-array]
    int *a[0];
           ^

J'oublie toujours que std=c++XX (au lieu de std=gnu++XX) ne désactive pas toutes les extensions.

Cela n'explique toujours pas le comportement sizeof. Mais au moins nous savons que ce n'est pas standard ...

40
bolov

En C++, un tableau de taille zéro est illégal.

ISO/IEC 14882: 2003 8.3.4/1:

[..] Si l'expression constante (5.19) est présente, il doit s'agir d'une expression constante intégrale et sa valeur doit être supérieure que zéro. L'expression constante spécifie la limite de (nombre d'éléments dans) du tableau. Si la valeur de l'expression constante est N, le tableau contient N éléments numérotés 0 à N-1, et le type de l'identifiant de D est “ dérivé-déclarateur-type-list tableau de N T ”. [..]

g ++ nécessite le -pedantic drapeau pour donner un avertissement sur un tableau de taille zéro.

18
msc

Les tableaux de longueur nulle sont une extension de GCC et Clang. Application de sizeof à des tableaux de longueur nulle évalue à zéro .

Une classe C++ (vide) ne peut pas avoir la taille 0, mais notez que la classe ZeroMemory n’est pas vide. Il a un membre nommé de taille 0 et l’application de sizeof renverra zéro.

4
haccks