Un pointeur vers un type incomplet peut-il être incomplet?

9

Peut int (*)[]être un type incomplet?

C 2018 6.2.5 1 dit:

À divers points d'une unité de traduction, un type d'objet peut être incomplet (manque d'informations suffisantes pour déterminer la taille des objets de ce type) ou complet (avoir suffisamment d'informations).

Il semble donc que si la taille d'un type est connue, le type est complet. 6.2.6.1 28 spécifie que certains types de pointeurs doivent avoir les mêmes tailles (pointeurs vers voidet caractères, pointeurs vers des types compatibles, pointeurs vers des structures et pointeurs vers des unions), mais les pointeurs vers d'autres types peuvent varier.

Dans une implémentation C où tous les pointeurs, ou tous les pointeurs vers des tableaux de int, ont la même taille, alors la taille de int (*)[]est connue, elle serait donc complète. Dans une implémentation qui, par exemple, utilise différents pointeurs pour les grands tableaux, la taille ne serait pas connue, elle est donc incomplète.

Comme le souligne MM , une structure ne doit pas contenir de membre de type incomplet, à l'exception d'un membre de tableau flexible final, conformément à une contrainte du 6.7.2.1 3. Cela suggère qu'une implémentation avec une taille de pointeurs doit accepter struct { int (*p)[]; }tandis qu'une implémentation qui a différents les tailles de ces tableaux doivent diagnostiquer une violation de contrainte. (Cela signifie à son tour qu'une telle déclaration ne fait pas partie d'un C. strictement conforme.)

Eric Postpischil
la source
6.2.5 (p22) aide? (ou ajoute-t-il plus de confusion permettant au type incomplet d'être complété par une déclaration ultérieure?)
David C. Rankin
@ DavidC.Rankin Dans 6.2.5 / 20, il est même dit que les pointeurs sont toujours des types complets
Christophe
@LanguageLawyer: En quoi cela serait-il pertinent? La question est "Y a-t-il un X qui n'est pas un Y?", Pas "Y a-t-il un X qui est un Y?"
Eric Postpischil
@LanguageLawyer: Le fait qu'il void *soit complet montre qu'un pointeur vers un type incomplet peut être complet. Il ne montre pas si un pointeur vers un type incomplet peut être incomplet. Si l'on demandait «Un mammifère peut-il être un éléphant?», Montrer que «Un lion est un mammifère» ne signifierait pas qu'un mammifère ne peut pas être un éléphant. La question demande si l'ensemble X de pointeurs de type incomplet peut contenir un élément incomplet. Il n'est pas pertinent de montrer que l'ensemble X de pointeurs sur type incomplet contient un élément complet.
Eric Postpischil
@EricPostpischil Oups. J'ai mal lu le titre: "Un pointeur vers un type incomplet peut-il être complet ?"
Law Lawyer

Réponses:

3

Un tableau de taille inconnue est incomplet:

Un type de tableau de taille inconnue est un type incomplet. Il est complété, pour un identifiant de ce type, en précisant la taille dans une déclaration ultérieure (avec liaison interne ou externe).

Le type int (*)[]n'est cependant pas incomplet: c'est un pointeur d'un tableau de inttaille inconnue.
Et un pointeur a une taille bien connue:

printf ("Size %d\n", sizeof(int (*)[]));

6.2.5 / 23: Un type a une taille constante connue s'il n'est pas incomplet et n'est pas un type de tableau de longueur variable.

De plus, vous pouvez même le déréférencer, grâce à la sémantique du tableau:

typedef int (*T)[];
...
int a[10];
for (int i=0; i<10; i++) a[i]=i;
T p=a;
for (int i=0; i<10; i++) printf ("%d ",(*p)[i]);
printf ("\n");

Éditer

De plus, un pointeur est toujours un type complet. Il est écrit noir sur blanc en 6.2.5 / 20:

Un type de pointeur peut être dérivé d'un type de fonction ou d'un type d'objet, appelé type référencé. Un type de pointeur décrit un objet dont la valeur fournit une référence à une entité du type référencé. Un type de pointeur dérivé du type référencé T est parfois appelé «pointeur vers T». La construction d'un type de pointeur à partir d'un type référencé est appelée «dérivation de type de pointeur». Un type de pointeur est un type d'objet complet.

Christophe
la source
Je pense que vous l'avez résumée et gcc est d'accord. struct w / pointeur vers un tableau incomplet est similaire à la question d'origine qui a déclenché la discussion.
David C. Rankin
Seul le dernier paragraphe est pertinent. L'exemple printfmontre seulement qu'un pointeur vers un tableau incomplet est complet dans l'implémentation dans laquelle il a été exécuté, comme indiqué dans la question - s'il ne s'agissait pas de 6.2.5 20, cité dans le dernier paragraphe, il pourrait ne pas être compilé. 6.2.5 23 n'est pas non plus pertinent; il nous dit que la taille est connue et constante si elle est complète, et nous savons déjà qu'être complet signifie que la taille est connue.
Eric Postpischil
6.2.5 20 est intéressant. Je suppose qu'il n'était pas destiné à avoir cette conséquence, mais cela signifie que tous les pointeurs vers des types complets qui ont le même type lorsqu'ils sont incomplets doivent avoir la même taille. Par exemple, tous les pointeurs vers des tableaux de intdoivent avoir la même taille les uns par rapport aux autres, et tous les pointeurs vers des tableaux d'un certain structdoivent avoir la même taille les uns par rapport aux autres, bien que tous les pointeurs vers des tableaux de types différents ne structdoivent pas nécessairement avoir la même taille comme les uns des autres.
Eric Postpischil
1
@EricPostpischil peut-être le texte "De même, les pointeurs vers des versions qualifiées ou non qualifiées de types compatibles doivent avoir les mêmes exigences de représentation et d'alignement." devrait être interprété comme disant qu'il T(*)[]doit avoir la même taille que T(*)[5], car ce sont des types compatibles et nous pourrions ajouter ou supprimer des qualificatifs
MM
Autoriser des types compatibles à avoir des tailles différentes entraînerait un tas de problèmes, c'est probablement un défaut que la norme ne l'exclut pas explicitement
MM