【问题标题】:Is it safe to access paddings in a structure or union?访问结构或联合中的填充是否安全?
【发布时间】: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 上触发。
  • su 中访问c[1] 是UB,不管任何对齐或填充。
  • 为什么不直接声明一些占用“填充”字节的变量呢?这样您就不必询问是否可以访问它们。

标签: c struct padding


【解决方案1】:

memcpy()memset() 或类似的整个结构是安全的,即使它包含填充位。但是,不能对填充保持其值做出任何假设。

因此,访问填充位的唯一用途是在某些情况下无需编写代码来避免访问它。

对于像memcmp() 这样的操作,访问填充位仍然是错误的,因为结果是不可预测的。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-05-20
    • 2014-09-14
    • 2021-10-15
    • 2018-05-08
    • 2015-11-07
    • 1970-01-01
    • 2023-03-29
    • 1970-01-01
    相关资源
    最近更新 更多