У меня есть союз в C, как это:
union AUnion {
struct CharBuf {
char *buf;
size_t len;
} charbuf;
uint8_t num;
double fp_num;
};
У меня вопрос, могу ли я гарантировать, что если дано следующее:
union AUnion u;
Тогда верно следующее:
&u == &u.num
&u == &u.fp_num
&u == &u.charbuf
Т.е. все они начинаются в начале сегмента памяти, где u
хранится.
В случае этой C-программы, скомпилированной с gcc version 5.3.0
а также -std=c11
вышеизложенное верно:
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
union AUnion {
struct CharBuf {
char *buf;
size_t len;
} charbuf;
uint8_t num;
double fp_num;
};
int main(void)
{
union AUnion u;
printf("%d\n", ((void*)&u) == ((void*)&u.charbuf));
printf("%d\n", ((void*)&u.charbuf) == ((void*)&u.num));
printf("%d\n", ((void*)&u.num) == ((void*)&u.fp_num));
}
Как это печатает:
1
1
1
Компиляция кода выше как C ++ 11 с тем же компилятором приводит к тому же выводу, что и компиляция C11.
Но это стандартизированное поведение? Это неопределенно? Могу ли я рассчитывать на такое поведение с большинством компиляторов Си? Можно ли ожидать такого поведения и с компиляторами C ++?
В 6.7.2.1p16 стандарт C гарантирует, что:
Размер союза достаточен, чтобы вместить самого большого из его членов. Значение не более одного из членов может быть сохранено в объекте объединения в любое время. Указатель на объект объединения, соответствующим образом преобразованный, указывает на каждого из его членов (или если элемент является битовым полем, то к единице, в которой он находится), и наоборот.
Так что да, вы можете положиться на всех членов, начиная с union
адрес (обратите внимание, это то же самое для первого члена struct
).
Стандарт C ++ включает аналогичное предложение в отношении стиля C (то есть только членов стиля C) union
s /struct
с, потому что C ++ позволяет передавать union
s-функции C, для которых требуется такая компоновка. Соответствующий раздел в стандарте C ++ — 9.5.
тем не мение, обратите внимание, что там может быть дополнение биты внутри стандартные простые типы (целые числа, числа с плавающей точкой). И их внутреннее может варьироваться (endianess). Вы также можете нарушать строгое правило алиасинга (С: эффективный тип).
Исходя из моего опыта, я бы сказал «да», хотя я проверил Стандарт C ++ 14 и это даже гарантирует это. (С ++ 11, скорее всего, будет иметь те же эффекты) Глава 9.5 гласит: All non-static data members of a union object have the same address
Таким образом, вы можете зависеть от этого поведения.