Czy wskaźnik do niekompletnego typu może być niekompletny?

9

Czy może int (*)[]być niekompletny?

C 2018 6.2.5 1 mówi:

W różnych punktach w jednostce tłumaczenia typ obiektu może być niekompletny (brak wystarczających informacji, aby określić rozmiar obiektów tego typu) lub kompletny (posiadający wystarczające informacje).

Wydaje się więc, że jeśli znany jest rozmiar typu, typ jest kompletny. 6.2.6.1 28 określa, że ​​niektóre typy wskaźników muszą mieć takie same rozmiary (wskaźniki do voidi znaki, wskaźniki do kompatybilnych typów, wskaźniki do struktur i wskaźniki do związków), ale wskaźniki do innych typów mogą się różnić.

W implementacji C, w której wszystkie wskaźniki lub wszystkie wskaźniki tablic intmają ten sam rozmiar, wówczas rozmiar int (*)[]jest znany, więc byłby kompletny. W implementacji, która, powiedzmy, używa różnych wskaźników dla dużych tablic, rozmiar nie byłby znany, więc jest niekompletny.

Jak wskazuje MM , struktura nie może zawierać elementu niepełnego typu, z wyjątkiem końcowego elastycznego elementu tablicy, zgodnie z ograniczeniem w 6.7.2.1 3. Sugeruje to, że implementacja z jednym rozmiarem wskaźników musi zaakceptować, struct { int (*p)[]; }podczas gdy implementacja ma inny rozmiary takich tablic muszą zdiagnozować naruszenie ograniczenia. (To z kolei oznacza, że ​​taka deklaracja nie jest częścią ściśle zgodnego C.)

Eric Postpischil
źródło
6.2.5 (p22) pomoc? (czy to wprowadza więcej zamieszania, umożliwiając uzupełnienie niekompletnego typu późniejszą deklaracją?)
David C. Rankin
@ DavidC.Rankin W wersji 6.2.5 / 20 powiedziano nawet, że wskaźniki są zawsze kompletnymi typami
Christophe
@LanguageLawyer: Jak by to miało znaczenie? Pytanie brzmi: „Czy istnieje X, który nie jest Y?”, A nie „Czy istnieje X, który jest Y?”
Eric Postpischil
@LanguageLawyer: Fakt, że void *jest kompletny, pokazuje, że wskaźnik do niekompletnego typu może być kompletny. Nie pokazuje, czy wskaźnik do niekompletnego typu może być niekompletny. Gdyby ktoś zapytał „Czy ssak może być słoniem?”, Wykazanie, że „Lew jest ssakiem” nie zapewniłoby, że ssak nie może być słoniem. Pytanie dotyczy tego, czy zestaw X wskaźników typu niepełnego może zawierać niekompletny element. Nie ma znaczenia, że ​​zestaw X wskaźników do niepełnego typu zawiera element, który jest kompletny.
Eric Postpischil,
@EricPostpischil Ups. Źle odczytałem tytuł jako „Czy wskaźnik do niekompletnego typu może być kompletny ?”
Język Lawyer

Odpowiedzi:

3

Tablica o nieznanym rozmiarze jest niekompletna:

Typ tablicy o nieznanym rozmiarze jest niepełnym typem. W przypadku identyfikatora tego typu uzupełnia się go, określając rozmiar w późniejszej deklaracji (z wewnętrznym lub zewnętrznym połączeniem).

Typ int (*)[]nie jest jednak niekompletny: jest wskaźnikiem tablicy into nieznanym rozmiarze.
Wskaźnik ma dobrze znany rozmiar:

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

6.2.5 / 23: Typ ma znany stały rozmiar, jeśli nie jest niekompletny i nie jest tablicą o zmiennej długości.

Ponadto możesz nawet wyrejestrować to, dzięki semantyce tablic:

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

Edytować

Ponadto wskaźnik jest zawsze kompletnym typem. Jest napisany czarno na białym w 6.2.5 / 20:

Typ wskaźnika może pochodzić z typu funkcji lub typu obiektu, zwanego typem odniesienia. Typ wskaźnika opisuje obiekt, którego wartość zapewnia odwołanie do encji określonego typu. Typ wskaźnika pochodzący od typu odniesienia T jest czasem nazywany „wskaźnikiem do T”. Konstrukcja typu wskaźnika z przywoływanego typu nazywa się „wyprowadzeniem typu wskaźnika”. Typ wskaźnika jest kompletnym typem obiektu.

Christophe
źródło
Myślę, że masz to ugotowane i gcc się zgadza. struct w / wskaźnik do niekompletnej tablicy jest podobny do pierwotnego pytania, które skłania do dyskusji.
David C. Rankin
Istotny jest tylko ostatni akapit. Przykład printfpokazuje tylko, że wskaźnik do niekompletnej tablicy jest kompletny w implementacji, w której został wykonany, jak stwierdzono w pytaniu - gdyby nie wersja 6.2.5 20, cytowana w ostatnim akapicie, kompilacja może się nie powieść. 6.2.5 23 również nie ma znaczenia; informuje nas, że rozmiar jest znany i stały, jeśli jest kompletny, i wiemy już, że bycie kompletnym oznacza, że ​​rozmiar jest znany.
Eric Postpischil
6.2.5 20 jest interesujące. Spekuluję, że nie miało to mieć takiego skutku, ale oznacza to, że wszystkie wskaźniki do uzupełnienia typów, które mają ten sam typ, gdy są niekompletne, muszą mieć ten sam rozmiar. Na przykład wszystkie wskaźniki do tablic intmuszą mieć taki sam rozmiar, a wszystkie wskaźniki do tablic określonego structmuszą mieć taki sam rozmiar, chociaż być może nie wszystkie wskaźniki do tablic różnego rodzaju structmuszą mieć ten sam rozmiar jak siebie nawzajem.
Eric Postpischil
1
@EricPostpischil może tekst „Podobnie wskaźniki do kwalifikowanych lub niekwalifikowanych wersji kompatybilnych typów powinny mieć takie same wymagania dotyczące reprezentacji i wyrównania”. należy zinterpretować, że T(*)[]musi mieć ten sam rozmiar co T(*)[5], ponieważ są one kompatybilnymi typami i możemy dodawać lub usuwać kwalifikatory
MM
Pozwalając zgodne typy mają różne rozmiary doprowadziłyby do całą masę problemów, to chyba wada, że norma nie wyklucza go wyraźnie
MM