C /C ++ структура неполный тип член несоответствие?

Допустим, мы определили две структуры в C или C ++ (я получаю одинаковый результат как в C, так и в C ++, и я думаю, что правила одинаковы, скажите, если они не совпадают).

элемент со значением типа неполного типа:

struct abc{
  int data;
  struct nonexsitnow next; //error: field ‘next’ has incomplete type, makes sense since "struct nonexsitnow" hasn't been declared or defined.
};

и один с указателем на член неполного типа:

struct abc{
  int data;
  struct nonexsitnow *next; //pass?!
};

Почему второе определение не вызывает проблем? Он использует struct nonexsitnow, который еще не был создан!

UPDATE:

Я заканчиваю этот лист из ответов и комментариев ниже, надеясь, что они правы и полезны для разработки.

Как упомянул @ArneVogel, оба struct Foo p; и struct Foo *p; - это неявное объявление Foo и struct Foo; явно делает эту работу (спасибо @Джон Боллинджеру). Это почти ничего не значит для , но имеет значение для и их поведение:

               In a situation where struct Foo is:
_______________________________________________________
|               | undeclared | declared but | defined |
|               |            | not defined  |         |
-------------------------------------------------------
|               |  C | C++   |  C  |  C++   | C | C++ |
-------------------------------------------------------
|struct Foo  p; |  × |  ×    |  ×  |   ×    | √ |  √  |
|struct Foo* p; |  √ |  √    |  √  |   √    | √ |  √  |
|       Foo  p; |  × |  ×    |  ×  |   ×    | × |  √  |
|       Foo* p; |  × |  ×    |  ×  |   √    | × |  √  |
12 голосов | спросил Alan Dawkins 30 Jpm1000000pmTue, 30 Jan 2018 16:46:42 +030018 2018, 16:46:42

3 ответа


0

Во-первых, вам нужно понять, что значит для типа быть "неполным". C определяет это так:

  

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

(C2011, 6.2.5 /1 )

Обратите внимание, что полнота типов зависит от области видимости и видимости объявлений, а не от внутренней характеристики типов. Тип может быть неполным в одной точке единицы перевода и завершаться в другой точке.

Однако

  

Тип указателя может быть получен из типа функции или типа объекта,   называется ссылочным типом. [...] Тип указателя является законченным объектом   Тип .

(C2011, 6.2.5 /20 ; акцент добавлен)

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

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

С другой стороны,

  

Структура или тип объединения неизвестного содержимого [...]   является неполным типом. Это завершено, для всех заявлений о том, что   тип, объявив ту же структуру или тег объединения с его определением   содержание позже в той же области.

(C2011, 6.2.5 /22 )

Это понятно, поскольку компилятор не может знать, насколько велик тип структуры, если он не знает, каковы его члены. Кроме того, имеет смысл, что

  

Структура или объединение не должны содержать члена с неполным или   тип функции (следовательно, структура не должна содержать экземпляр   сам, но может содержать указатель на экземпляр самого себя ), кроме   что последний член структуры с более чем одним именованным членом   может иметь неполный тип массива [...].

(C2011, 6.7.2.1/3 ; акцент добавлен)

Исключение описывает компонент C, называемый «членом гибкого массива», который имеет несколько предостережений и ограничений. Это тангенциальный вопрос, о котором вы можете прочитать (или спросить) отдельно.

Кроме того, все вышесказанное согласуется с тем фактом, что C и C ++ позволяют ссылаться на тип структуры по его тегу до объявления его членов; то есть когда оно неполное. Это можно сделать самостоятельно как предварительную декларацию ...

struct foo;

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

Действительно, относительно распространенным вариантом использования является реализация непрозрачных типов. В таком случае библиотека создает и использует тип данных, реализацию которого она не хочет раскрывать по любой из множества причин. Тем не менее, он может выдавать указатели с соответствующим типом на экземпляры таких структур клиентскому коду и ожидать получения таких указателей обратно. Если это никогда не обеспечиваетопределение ссылочного типа, тогда клиентский код должен обрабатывать ссылочные объекты как непрозрачные BLOB-объекты.

ответил John Bollinger 31 Jam1000000amWed, 31 Jan 2018 00:08:45 +030018 2018, 00:08:45
0
  

Почему второе определение структуры не вызывает проблем?

Потому что это указатель. Размер указателя известен компилятору, даже если тип, на который указывает указатель, является неполным.

ответил ネロク 30 Jpm1000000pmTue, 30 Jan 2018 16:48:05 +030018 2018, 16:48:05
0

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

На данной платформе sizeof(T*) всегда будет возвращать одно и то же значение для любого типа T, являющегося типом структуры или класса.

Вот почему вы можете использовать указатели для заранее объявленных типов без ошибок. Конечно, для доступа к содержимому объекта, на который указывает такой указатель или разыменования, должно быть предоставлено определение. Однако вы можете присвоить значение такому указателю (если это разрешено с точки зрения совместимости типов).

Важный факт:

В C, где вы обычно используете так называемое «приведение в стиле C», назначение указателей обычно может выполняться независимо от типов (вы несете ответственность за обеспечение правильного поведения и выполнения требований выравнивания).

В C ++, однако, возможно ли приведение между неполными типами, зависит от типа преобразования. Рассмотрим два полиморфных типа:

class A; // forward declaration only
class B; // forward declaration only, actually inherits from A

A* aptr;
B* bptr;

bptr = (B*)(aptr); // ok
bptr = dynamic_cast<B*>(aptr); // error

dynamic_cast<> завершится ошибкой, если у компилятора нет доступа к определению типов, участвующих в приведении (что необходимо для выполнения проверять). Пример: Ideone .

ответил Mateusz Grzejek 30 Jpm1000000pmTue, 30 Jan 2018 16:55:31 +030018 2018, 16:55:31

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132