Пустые структуры в C

http://c0x.coding-guidelines.com/6.7.2.1.html:

1401 Если список-декларации-структуры не содержит именованных членов, поведение не определено.

Означает ли это, что следующее является незаконным?

struct C { };

Или что это значит?

Я использовал Convention=>C указатель Ada на пустую структуру (фактически пустую запись Ada) для обслуживания void* в моих привязках библиотеки C (потому что в Ada нет void*). Интересно, не так ли это?

Что я неправильно понял?


См. Также «Не передавать и не возвращать структуры без полей ненулевого размера в функции extern (C). Согласно C11 6.7.2.1p8 это неопределенное поведение». на https://dlang.org/spec/struct.html


person porton    schedule 27.12.2018    source источник
comment
struct C{ }; даже не соответствует стандартизированному синтаксису. struct C { _Static_assert(1,""); }; (_Static_assert - ненужное уродство), но для этого у вас есть UB, если внутри структуры нет именованных членов (port70.net/~nsz/c/c11/n1570.html#6.7.2.1p8).   -  person PSkocik    schedule 04.01.2019


Ответы (2)


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

C 2018 6.7.2.1 8 частично говорит:

Если список-декларации-структуры не содержит именованных членов, ни напрямую, ни через анонимную структуру или анонимное объединение, поведение не определено.

Если вам нужно что-то, служащее «неизвестным типом», и вы не хотите использовать void, вы можете объявить структуру, тег которой известен, а содержимое - нет, например:

struct foo;

Затем вы можете использовать указатели на такие структуры (например, вы можете определить указатель struct foo *p;), но компилятор не будет знать размер или содержимое таких структур, поэтому он не может помочь вам выделить их, управлять их массивами или иным образом использовать их, кроме как путем передачи указателей и запроса внешних подпрограмм (которые действительно знают о содержимом).

Обычно при операциях между подпрограммами C в одном модуле и подпрограммами C в другом модуле:

  • В одном исходном модуле, который не знал о содержимом структуры, вы использовали бы указатель (struct foo *).
  • Другой исходный модуль (часто это какая-то программная библиотека) будет знать о содержимом структуры. В собственном исходном коде он определил бы полную структуру с помощью struct foo { /* various things */ };, и он будет выполнять службы для этой структуры для первого модуля.
  • Между двумя такими модулями C правила стандарта C будут определять поведение.

Поскольку вы взаимодействуете между C и Ada, правила для этих взаимодействий должны предоставляться вашими реализациями C и Ada.

person Eric Postpischil    schedule 27.12.2018
comment
Хм, ну а почему говорят, что sizeof(struct C)==1 для struct C { };, если он вообще не определен? - person porton; 28.12.2018
comment
@porton: Кто такие «они»? Я предполагаю, что вы спрашиваете о странице по одной из ваших ссылок. он говорит что-то о g ++ и clang ++, производящих 1 для sizeof. Напомним, что очень мало незаконного в C. Компиляторам разрешено расширять язык. Поскольку стандарт C не определяет, что происходит с пустой структурой, компилятор может определять, что происходит, пока вы используете этот компилятор. - person Eric Postpischil; 28.12.2018
comment
@porton • struct C { }; не означает, что он вообще не определен, это означает, что он определен. struct C; объявлен, но не определен, поэтому struct foo* ptr; работает. Пустая структура имеет ненулевой размер, потому что для адреса требуется ненулевой размер; думайте об этом как о байтах заполнения и / или байтах выравнивания. - person Eljay; 14.05.2020

С точки зрения написания привязки Ada к библиотеке C не имеет значения, какой тип доступа Ada Convention-C использовать для обозначений void*. Вы никогда не собираетесь ничего делать с объектами этого типа, кроме как передавать их импортированным функциям C. Я обычно использую

type Void_Ptr is access all Integer;
pragma Convention (C, Void_Ptr);
person Jeffrey R. Carter    schedule 04.01.2019
comment
Думаю, ты ошибаешься. Выравнивание целых чисел и структур может быть разным - person porton; 05.01.2019
comment
Выравнивания различных типов не имеют отношения к определению void*. - person Jeffrey R. Carter; 05.01.2019