Может ли указатель на неполный тип быть неполным?

9

Может int (*)[]быть неполного типа?

C 2018 6.2.5 1 говорит:

В различных точках в единице перевода тип объекта может быть неполным (без достаточной информации для определения размера объектов этого типа) или полным (имеющим достаточную информацию).

Таким образом, кажется, что если размер типа известен, тип завершен. 6.2.6.1 28 указывает, что определенные типы указателей должны иметь одинаковые размеры (указатели на voidи символы, указатели на совместимые типы, указатели на структуры и указатели на объединения), но указатели на другие типы могут различаться.

В реализации C, где все указатели или все указатели на массивы intимеют одинаковый размер, тогда размер int (*)[]известен, поэтому он будет завершен. В реализации, которая, скажем, использует разные указатели для больших массивов, размер не будет известен, поэтому он является неполным.

Как указывает MM , структура не должна содержать элемент с неполным типом, за исключением конечного элемента гибкого массива, согласно ограничению в 6.7.2.1. 3. Это предполагает, что реализация с указателями одного размера должна принимать, в struct { int (*p)[]; }то время как реализация с другим размеры для таких массивов должны диагностировать нарушение ограничения. (Это, в свою очередь, означает, что такое объявление не является частью строго соответствующего C.)

Эрик Постпищил
источник
6.2.5 (p22) помочь? (или это добавляет больше путаницы, позволяющей заполнить неполный тип последующим объявлением?)
Дэвид К. Ранкин
@ DavidC.Rankin В 6.2.5 / 20 даже сказано, что указатели всегда полные типы
Кристоф
@LanguageLawyer: Как бы это было актуально? Вопрос в том, «есть ли X, который не является Y?», А не «есть ли X, который является Y?»
Эрик Постпищил
@LanguageLawyer: тот факт, что void *завершено, показывает, что указатель на неполный тип может быть завершен. Он не показывает, может ли указатель на неполный тип быть неполным. Если бы кто-то спросил: «Может ли млекопитающее быть слоном?», Показ того, что «Лев - это млекопитающее», не означает, что млекопитающее не может быть слоном. Вопрос состоит в том, может ли множество указателей X иметь неполный тип и содержать элемент, который является неполным. Показывать, что множество X указателей на неполный тип содержит полный элемент, не имеет значения.
Эрик Постпишил
@EricPostpischil Упс. Я неправильно прочитал заголовок как "Может ли указатель на неполный тип быть полным ?"
Языковой адвокат

Ответы:

3

Массив неизвестного размера является неполным:

Тип массива неизвестного размера является неполным типом. Для идентификатора этого типа он завершается указанием размера в последующем объявлении (с внутренней или внешней связью).

Тип, int (*)[]однако, не является неполным: это указатель на массив intнеизвестного размера.
И указатель имеет хорошо известный размер:

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

6.2.5 / 23: тип имеет известный постоянный размер, если тип не является неполным и не является типом массива переменной длины.

Более того, вы даже можете разыменовать его, благодаря семантике массива:

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

редактировать

Кроме того, указатель всегда является полным типом. В 6.2.5 / 20 написано черным по белому:

Тип указателя может быть получен из типа функции или типа объекта, называемого ссылочным типом. Тип указателя описывает объект, значение которого предоставляет ссылку на объект ссылочного типа. Тип указателя, полученный из ссылочного типа T, иногда называют «указателем на T». Конструкция типа указателя из ссылочного типа называется «выводом типа указателя». Тип указателя является полным типом объекта.

Christophe
источник
Я думаю, что у вас есть все, и GCC соглашается. Структура с указателем на неполный массив аналогична исходному вопросу, вызывающему обсуждение.
Дэвид С. Ранкин
Только последний абзац уместен. Этот пример printfтолько показывает, что указатель на неполный массив завершен в реализации, в которой он был выполнен, как указано в вопросе - если бы не было 6.2.5 20, процитированного в последнем абзаце, он мог бы не скомпилироваться. 6.2.5 23 тоже не актуально; он говорит нам, что размер известен и постоянен, если он завершен, и мы уже знаем, что значение «полный» означает, что размер известен.
Эрик Постпишил
6.2.5 20 интересно. Я предполагаю, что это не было предназначено для того, чтобы иметь это следствие, но это означает, что все указатели на завершение типов, которые имеют один и тот же тип, когда неполное должно иметь одинаковый размер. Например, все указатели на массивы intдолжны иметь одинаковый размер, а все указатели на массивы определенного structразмера должны иметь одинаковый размер, хотя, возможно, не все указатели на массивы различных типов structдолжны иметь одинаковый размер. как друг друга.
Эрик Постпишил
1
@EricPostpischil, возможно, текст «Аналогично, указатели на квалифицированные или неквалифицированные версии совместимых типов должны иметь одинаковые требования к представлению и выравниванию». следует интерпретировать так, чтобы T(*)[]они имели одинаковый размер T(*)[5], так как они являются совместимыми типами, и мы можем добавлять или удалять квалификаторы
MM
Разрешение совместимым типам иметь разные размеры может привести к целой куче проблем, вероятно, это недостаток, который стандарт явно не исключает
MM