Предположим, что у меня есть некоторые структуры, определенные как:
struct foo { int a; };
struct bar { struct foo r; int b; };
struct baz { struct bar z; int c; };
Является ли стандарт C гарантией того, что следующий код строго соответствует?
struct baz x;
struct foo *p = (void *)&x;
assert(p == &x.z.r);
Мотивация для этой конструкции состоит в том, чтобы обеспечить согласованную идиому программирования для приведения к типу указателя, который, как известно, совместим.
Теперь, это то, что C говорит о том, как структуры и его исходные элементы конвертируются:
Внутри объекта структуры члены небитного поля и единицы, в которых расположены битовые поля, имеют адреса, которые увеличиваются в том порядке, в котором они объявлены. Указатель на объект структуры, соответствующим образом преобразованный, указывает на его первоначальный член (или если этот элемент является битовым полем, а затем блоку, в котором он находится) и наоборот. В структурном объекте может быть неназванное дополнение, но не в его начале.
C.11 & sect; 6.7.2.1 & para; 15
Это то, что он говорит о преобразованиях void
указателей:
Указатель на
void
может быть преобразован в или из указателя на любой тип объекта. Указатель на любой тип объекта может быть преобразован в указатель наvoid
и обратно; результат сравнивается с исходным указателем.
C.11 & sect; 6.3.2.3 & para; 1
И вот что он говорит об конвертации между типами указателей объектов:
Указатель на тип объекта может быть преобразован в указатель на другой тип объекта. Если результирующий указатель неправильно выровнен 68) для ссылочного типа, поведение undefined. В противном случае, если преобразовать обратно, результат будет сравниваться с исходным указателем. 68) В общем, понятие "правильно выровнено" транзитивно: если указатель на тип A правильно выровнен для указатель на тип B, который, в свою очередь, правильно выровнен для указателя на тип C, тогда указатель на тип A правильно выровнен для указателя на тип C.
C.11 & sect; 6.3.2.3 & para; 7
Мое понимание из вышеизложенного заключается в том, что преобразование указателя объекта в указатель объекта другого типа с помощью преобразования void *
отлично. Но у меня есть комментарий, который предполагает иное.