Гарантируется ли этот код стандартом C? - PullRequest
7 голосов
/ 11 октября 2011

Я читал, что если вы объявите две структуры, подобные этой:

struct Node {
   int a, b, c;
};

struct DerivedNode {
   struct Node base;
   int d, e, f;
};

Тогда вы можете использовать указатели на них следующим образом:

struct DerivedNode myDerivedNode; 
struct Node *regularNode = (struct Node *) &myDerivedNode;

regularNode->a = 3;

Другими словами, смещения адресов для a, b, c одинаковы в пределах struct Node и struct DerivedNode. Таким образом, вы можете извлечь из него своего рода полиморфизм, при котором вы можете принудительно передать указатель DerivedNode (struct Node *) -cast везде, где обычно берется указатель Node.

Мой вопрос: гарантировано ли это поведение? Я знаю, что есть некоторые странные проблемы с выравниванием памяти, и что компилятор иногда переупорядочивает поля для лучшей упаковки в памяти. Будет ли когда-нибудь располагаться поле base, кроме начала struct DerivedNode?

Ответы [ 3 ]

13 голосов
/ 11 октября 2011

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

Соответствующие выдержки из стандарта ANSI C:

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

Это означает, что элементы располагаются последовательно.

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

означает, что первый элемент размещен со смещением 0.

Примечание: Стандартные выдержки из раздела6.7.2.1 ИСО / МЭК 9899: проект ТС3, сентябрь 2007 г.

3 голосов
/ 11 октября 2011

Как утверждает Дэвид, это гарантировано, пока base остается первым элементом в DerivedNode.

Но в целом это плохая практика.Я не могу понять много обстоятельств, когда вы не можете сказать

struct Node *regularNode = &myDerivNode.base;

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

1 голос
/ 11 октября 2011

Это не ответит на ваш вопрос, но тот, кто хочет написать стандарт ANSI (ISO) C, может скомпилировать свой код с gcc -pedantic или -pedantic-errors.Эти параметры должны вызывать предупреждения / ошибки компиляции в нестандартных строках кода.

Обратите внимание, что это не на 100% эффективно, начиная с man gcc:

[- pedantic] находит некоторые практики, отличные от ISO, но не все - только те, для которых ISO C требует диагностики, и некоторые другие, для которых диагностика была добавлена.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...