我们可以使用static_assert来检测结构中的填充吗?

时间:2018-01-08 10:33:41

标签: c struct static-assert

这是对其他question

的跟进

我试图在编译时建立一个特定的实现是否在结构中添加了未命名的填充。像gcc这样的特定实现允许使用pragma来控制结构中的填充和对齐,但代价是与其他实现的兼容性。由于C11的n1570草案需要static_assertoffset_of,我想使用它们来查看实现是否在成员之间使用填充。

以下是代码的相关部分(引用问题中的完整代码):

#include <stdio.h>
#include <stddef.h>
#include <assert.h>

struct quad {
    int x;
    int y;
    int z;
    int t;
};

int main() {
    // ensure members are consecutive (note 1)
    static_assert(offsetof(struct quad, t) == 3 * sizeof(int),
        "unexpected padding in quad struct");
    struct quad q;
    ...

如6.7.2.1结构和联合说明符§15所说:

  

在结构对象内,非位字段成员和位域中的单位   驻留的地址按声明的顺序增加。指向a的指针   结构对象,适当转换,指向其初始成员(或者如果该成员是a   位字段,然后到它所在的单元,反之亦然。可能有未命名的   在结构对象中填充,但不在其开头。

我假设如果结构中元素的偏移量是在它之前声明的元素大小的总和,那么这些元素之间不存在填充,它们应该连续分配,因此如果它们是同类型。

问题是:上述假设是错误的,它是(对参考问题的评论让我们想一想)为什么?

1 个答案:

答案 0 :(得分:5)

理论上可能在t之后的结构末尾填充,你的断言没有捕获(可能是也可能不是)。您的假设是正确的,这可以很好地使用offsetofstatic_assert来检测成员变量之间的任何位置。

更好的选择可能是:

static_assert( offsetof(struct quad, t) == sizeof(struct quad)-sizeof(int),

这也会在结构的末尾捕获填充。此外,如果在代码维护期间更改了struct成员,它会使断言更加灵活。