Позиция памяти элементов в объединении C/С++
У меня есть объединение в 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
I. все они начинаются в начале сегмента памяти, где хранится 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
Компиляция кода выше как С++ 11 с тем же результатом компилятора в том же выпуске, что и компиляция C11.
Но это стандартизированное поведение? Это undefined? Могу ли я полагаться на это поведение с большинством компиляторов C? Могу ли я ожидать такого поведения с компиляторами С++?
Ответы
Ответ 1
В 6.7.2.1p16 стандарт C гарантирует, что:
Размер объединения достаточен, чтобы содержать самый большой из его членов. Значение не более одного из членов может быть сохранено в объединенном объекте в любое время. Указатель на объект объединения, соответствующим образом преобразованный, указывает на каждый из его членов (или если элемент является битовым полем, а затем блоку, в котором он находится) и наоборот.
Итак, да, вы можете положиться на всех участников, начиная с адреса union
(обратите внимание, что это одно и то же для первого члена struct
).
В стандарте С++ есть аналогичное предложение относительно C-стиля (т.е. только члены стиля C) union
s/struct
s, потому что С++ позволяет передавать union
в C-функции, которые требуют этого макета. Соответствующий раздел в стандарте С++ - 9.5.
Однако, обратите внимание, что в стандартных простых типах (целые числа, поплавки) могут быть биты заполнения. И их внутренние могут отличаться (endianess). Вы также можете нарушить правило строгого сглаживания (C: эффективный тип).
Ответ 2
Из моего опыта я бы сказал "да", хотя я проверил С++ 14 стандарт, и это даже гарантирует это. (С++ 11, скорее всего, будут иметь одинаковые эффекты). Глава 9.5: All non-static data members of a union object have the same address
Итак, вы можете зависеть от этого поведения.