【发布时间】:2018-06-06 06:11:22
【问题描述】:
考虑一下这段代码。保证存在填充。
static_assert(_Alignof(char) < _Alignof(double), "Flip!");
static_assert(sizeof(char) < sizeof(double), "Flop!");
struct S {
char c[1];
double d;
};
union U {
char c[1];
double d;
};
static_assert(sizeof(struct S) == _Alignof(double) * sizeof(double), "Fudge!");
static_assert(sizeof(union U) == sizeof(double), "Futz!");
S s; U u;
s.c[1] = 0; // What?
u.c[1] = 0; // What?
对于那些static_asserts,可以肯定在中间或末尾有填充。访问它们是否安全?
【问题讨论】:
-
Afaik 这是 UB,因为允许编译器尽可能在调试构建中对数组进行边界检查。至于 punnig 类型,有一个问题:Is type-punning through a union unspecified in C99, and has it become specified in C11? Ask
-
alligbnment 对重载数组的影响不大,通常不会被检测到,因为邻居字段,但
c[1]是一个错误 -
您无法可靠地访问填充。您不能依赖在结构(联合)分配下复制的填充。从那里有字节的意义上来说,访问它们是“安全的”。你可以用它们做任何有意义或可靠的事情。如果您使用此类字节,请明确说明:
struct S2 { char c[1]; short s; int i; double d; }(在大多数系统上,除了 32 位 Intel x86,它的大小与问题中的struct S相同)。而且我相信您的第一个静态断言会在 32 位 x86 上触发。 -
在
s或u中访问c[1]是UB,不管任何对齐或填充。 -
为什么不直接声明一些占用“填充”字节的变量呢?这样您就不必询问是否可以访问它们。