N. *_*avy 17 c gcc struct initialization
如果C编译器填充结构以便将字段与其原始对齐对齐,然后初始化该结构,则填充是否初始化为零?
例如以下结构:
typedef struct foo_t_ {
int a;
char b;
int c;
char d;
} foo_t;
Run Code Online (Sandbox Code Playgroud)
在许多系统上,这个(设计不佳)的结构将具有sizeof(foo_t)
16个,总共6个字节的填充,每个字符后3个字节.
如果我们初始化结构,如:
foo_t foo = { .a = 1, .b = '2' };
Run Code Online (Sandbox Code Playgroud)
然后字段foo.a
将设置为1并将foo.b
设置为字符"2".未指定的字段(`foo.c'和'foo.d')将自动设置为0.问题是,6个字节的填充会发生什么?那还会自动设置为0吗?还是未定义的行为?
用例是我将计算数据结构的哈希值:
foo_t foo = { .a = 1, .b = '2' };
foo_t bar = { .a = 1, .b = '2' };
uint32_t hash_foo = calc_hash(&foo, sizeof(foo));
uint32_t hash_bar = calc_hash(&bar, sizeof(bar));
Run Code Online (Sandbox Code Playgroud)
我想确定hash_foo
并且hash_bar
是一样的.我可以通过首先使用memset()
清除结构然后初始化它来保证这一点,但是使用C初始化代替它似乎更清晰.
在实践中,我的系统上的GCC也确实清除了填充,但我不知道这是否有保证.
Sou*_*osh 15
一般而言,C11
对于任何未初始化的对象章节§6.2.6.1/ 6,
当值存储在结构或联合类型的对象中(包括在成员对象中)时,对应于任何填充字节的对象表示的字节采用未指定的值.
但是,如果部分初始化完成,那么对于其余的成员,初始化就像一个具有静态或线程存储持续时间的对象,然后引用相同的标准,章节§6.7.9/ 21
如果括号括起的列表中的初始值设定项少于聚合的元素或成员,或者用于初始化已知大小的数组的字符串文字中的字符数少于数组中的元素,则聚合的其余部分应为隐式初始化与具有静态存储持续时间的对象相同.
关于具有静态存储持续时间的对象的隐式初始化,第10段
如果未显式初始化具有静态或线程存储持续时间的对象,则:
- 如果它是一个聚合,则根据这些规则初始化(递归)每个成员,并将任何填充初始化为零比特;
因此,在您的情况下,其余对象的填充保证为0,但不适用于已接收初始化程序的成员.
所以,到处都是,你不应该依赖0 的隐式初始化,使用memset()
.
话虽这么说,无论如何,不建议(必需)依赖填充字节,如果有的话.使用确切的成员变量并根据这些值计算哈希值.