C结构体初始化时的填充问题

4

I have a struct such as

typedef struct
{
    int a;  // Let's say this ends up being 4 bytes
    int b;  // 4 bytes
    char text[10]; // 10 bytes
} blah_t;

static blah_t myvar;
  1. 假设在blah_t中字段大小的总和为18个字节,但由于填充,sizeof(blah_t)为20。
  2. myvar是静态变量,因此它将被初始化为零。

问题:

  1. 对于静态变量,填充字节19和20是否保证为0? 如果不是,则需要对任何结构体的memcmp进行有效验证–即使对于静态变量,也需执行memset(&myvar, 0, sizeof(blah_t))
  2. 那么对于calloc(1, sizeof(blah_t))呢?字节19和20是否保证为零?我相信是这样的。
3个回答

5
根据ISO C99标准:“当一个值存储在结构体或联合类型的对象中时,包括成员对象,在任何填充字节中对应的对象表示的字节都采用未指定的值。”
进一步查看,这似乎涉及一些其他问题:C和C ++中结构体比较
编辑:虽然并不是完全重复的问题,但有许多常见问题都有详细的回答。

引用标准是很好的,你能给出“章节和段落”吗?在C2011(ISO/IEC 9899:2011)中,它在§6.2.6类型的表示和子节§6.2.6.1通用中,第6段。 - Jonathan Leffler
好的,我本来想加上的,但是忘记了。6.2.6.1类型的表示,第6段。 - Randy Howard
我没有看到你提到的C++问题有任何重复。 C++类是一种不同的东西。 我希望找到的是......如果规范中是否描述了如何初始化特定情况下的静态变量。 - B. Nadolson
1
它明确指出填充值具有未指定的值,因此您不能真正信任memcmp()在可移植性方面“做正确的事情”。 - Randy Howard
在这两种情况下,程序的启动发生在执行环境调用指定的C函数时。所有具有静态存储期限的对象都必须在执行环境调用指定的C函数时初始化(设置为其初始值)才能进行程序启动。此类初始化的方式和时间是未指定的。因此,即使对于静态结构体,填充似乎也未定义。 - B. Nadolson
2
这个答案可能需要更新以适应C11的更改。当静态变量没有显式初始化时,填充位被设置为零。我添加了一个答案 - afk

2
兰迪·霍华德的被接受的答案在 C11 中已经不太准确了。

静态变量的填充字节 19 和 20 是否保证为 0?

  1. 在 C11 中,是的,当静态变量没有显式初始化时,填充位被设置为零。C11 Standard,子句6.7.9,第10段:

. . . 如果具有静态或线程存储期限的对象未明确初始化,则:...如果它是一个聚合体,则根据这些规则递归地初始化每个成员,并且任何填充都将被初始化为零位...

  1. 是的,calloc 将清零结构的整个 sizeof(包括填充)。

其他有用和相关的链接:


0
填充字节19和20。这些对于静态变量保证为0吗?
请参考Randy Howard的答案。
那么calloc(1,sizeof(blah_t))呢?字节19/20是否保证为零?
是的。calloc会将内存清零。
出于好奇,我想知道您为什么关心填充。可移植代码不应该涉及任何表示方面(填充,字节序等)。

我想对比使用memcmp函数对一个静态结构体和一个通过calloc分配的结构体。我知道当涉及存储时,填充行为是未定义的,但在规范中,静态分配的结构体可能被视为“存储”,也可能不被视为“存储”。我正在寻找非常技术性的区别。 - B. Nadolson
对于可移植性来说并不重要,但对于安全性来说可能很重要。自动分配变量的填充未初始化时,信息可能会从堆栈泄漏。 - Nick Desaulniers

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接