Kann ein Zeiger auf einen unvollständigen Typ unvollständig sein?

9

Kann int (*)[]ein unvollständiger Typ sein?

C 2018 6.2.5 1 sagt:

An verschiedenen Stellen innerhalb einer Übersetzungseinheit kann ein Objekttyp unvollständig (ohne ausreichende Informationen zur Bestimmung der Größe von Objekten dieses Typs) oder vollständig (mit ausreichenden Informationen) sein.

Wenn also die Größe eines Typs bekannt ist, scheint der Typ vollständig zu sein. 6.2.6.1 28 gibt an, dass bestimmte Zeigertypen dieselbe Größe haben müssen (Zeiger auf voidund Zeichen, Zeiger auf kompatible Typen, Zeiger auf Strukturen und Zeiger auf Gewerkschaften), Zeiger auf andere Typen können jedoch variieren.

In einer C-Implementierung, in der alle Zeiger oder alle Zeiger auf Arrays von intdieselbe Größe haben, ist die Größe von int (*)[]bekannt, sodass sie vollständig wäre. In einer Implementierung, die beispielsweise unterschiedliche Zeiger für große Arrays verwendet, ist die Größe nicht bekannt, sodass sie unvollständig ist.

Wie MM hervorhebt, darf eine Struktur kein Element mit unvollständigem Typ enthalten, mit Ausnahme eines endgültigen flexiblen Array-Elements gemäß einer Einschränkung in 6.7.2.1 3. Dies legt nahe, dass eine Implementierung mit einer Zeigergröße akzeptiert werden muss, struct { int (*p)[]; }während eine Implementierung eine andere hat Größen für solche Arrays müssen eine Einschränkungsverletzung diagnostizieren. (Dies bedeutet wiederum, dass eine solche Erklärung nicht Teil der strikten Einhaltung von C ist.)

Eric Postpischil
quelle
6.2.5 (p22) helfen? (Oder führt dies zu mehr Verwirrung, sodass der unvollständige Typ durch eine spätere Deklaration vervollständigt werden kann?)
David C. Rankin,
@ DavidC.Rankin In 6.2.5 / 20 heißt es sogar, dass Zeiger immer vollständige Typen sind
Christophe
@LanguageLawyer: Wie wäre das relevant? Die Frage ist: "Gibt es ein X, das kein Y ist?", Nicht "Gibt es ein X, das ein Y ist?"
Eric Postpischil
@LanguageLawyer: Die Tatsache, dass void *vollständig ist, zeigt, dass ein Zeiger auf einen unvollständigen Typ vollständig sein kann. Es wird nicht angezeigt, ob ein Zeiger auf einen unvollständigen Typ unvollständig sein kann. Wenn man fragt: "Kann ein Säugetier ein Elefant sein?", Wenn man zeigt, dass "Ein Löwe ein Säugetier ist", würde dies nicht bedeuten, dass ein Säugetier kein Elefant sein kann. Die Frage fragt, ob die Menge X von Zeigern auf unvollständigen Typ ein Element enthalten kann, das unvollständig ist. Es ist irrelevant zu zeigen, dass die Menge X von Zeigern auf unvollständigen Typ ein Element enthält, das vollständig ist.
Eric Postpischil
@EricPostpischil Ups. Ich habe den Titel falsch verstanden als "Kann ein Zeiger auf einen unvollständigen Typ vollständig sein ?"
Sprachanwalt

Antworten:

3

Ein Array unbekannter Größe ist unvollständig:

Ein Array-Typ unbekannter Größe ist ein unvollständiger Typ. Für einen Bezeichner dieses Typs wird die Angabe der Größe in einer späteren Deklaration (mit interner oder externer Verknüpfung) abgeschlossen.

Der Typ ist int (*)[]jedoch nicht unvollständig: Es ist ein Zeiger auf ein Array intunbekannter Größe.
Und ein Zeiger hat eine bekannte Größe:

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

6.2.5 / 23: Ein Typ hat eine bekannte konstante Größe, wenn der Typ nicht unvollständig ist und kein Array-Typ mit variabler Länge ist.

Darüber hinaus können Sie es dank der Array-Semantik sogar dereferenzieren:

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");

Bearbeiten

Außerdem ist ein Zeiger immer ein vollständiger Typ. Es ist in 6.2.5 / 20 schwarz auf weiß geschrieben:

Ein Zeigertyp kann von einem Funktionstyp oder einem Objekttyp abgeleitet werden, der als referenzierter Typ bezeichnet wird. Ein Zeigertyp beschreibt ein Objekt, dessen Wert einen Verweis auf eine Entität des referenzierten Typs bereitstellt. Ein Zeigertyp, der vom referenzierten Typ T abgeleitet ist, wird manchmal als "Zeiger auf T" bezeichnet. Die Konstruktion eines Zeigertyps aus einem referenzierten Typ wird als Ableitung des Zeigertyps bezeichnet. Ein Zeigertyp ist ein vollständiger Objekttyp.

Christophe
quelle
Ich denke du hast es auf den Punkt gebracht und gcc stimmt zu. Die Struktur mit dem Zeiger auf ein unvollständiges Array ähnelt der ursprünglichen Frage, die die Diskussion veranlasst.
David C. Rankin
Nur der letzte Absatz ist relevant. Das Beispiel printfzeigt nur, dass ein Zeiger auf ein unvollständiges Array in der Implementierung, in der es ausgeführt wurde, vollständig ist, wie in der Frage angegeben. Ohne 6.2.5 20, wie im letzten Absatz angegeben, kann er möglicherweise nicht kompiliert werden. 6.2.5 23 ist ebenfalls nicht relevant; Es sagt uns, dass die Größe bekannt und konstant ist, wenn sie vollständig ist, und wir wissen bereits, dass die Größe bekannt ist, wenn sie vollständig ist.
Eric Postpischil
6.2.5 20 ist interessant. Ich spekuliere, dass es nicht beabsichtigt war, diese Konsequenz zu haben, aber es bedeutet, dass alle Zeiger auf vollständige Typen, die denselben Typ haben, wenn sie unvollständig sind, dieselbe Größe haben müssen. Beispielsweise müssen alle Zeiger auf Arrays von intdieselbe Größe haben, und alle Zeiger auf Arrays einer bestimmten structGröße müssen dieselbe Größe haben, obwohl möglicherweise nicht alle Zeiger auf Arrays unterschiedlicher Art structdieselbe Größe haben müssen wie einander.
Eric Postpischil
1
@EricPostpischil möglicherweise der Text "In ähnlicher Weise müssen Zeiger auf qualifizierte oder nicht qualifizierte Versionen kompatibler Typen dieselben Darstellungs- und Ausrichtungsanforderungen haben." sollte so interpretiert werden, dass T(*)[]es die gleiche Größe haben muss wie T(*)[5], da es sich um kompatible Typen handelt und wir Qualifikationsmerkmale hinzufügen oder entfernen könnten
MM
Das Zulassen, dass kompatible Typen unterschiedliche Größen haben, würde zu einer ganzen Reihe von Problemen führen. Es ist wahrscheinlich ein Fehler, den der Standard nicht explizit ausschließt
MM