为什么初始化C联合会使用;“指定初始值设定人”;给出随机值?

为什么初始化C联合会使用;“指定初始值设定人”;给出随机值?,c,initialization,c99,unions,buffer-overflow,C,Initialization,C99,Unions,Buffer Overflow,我有一个“臭虫”,我花了很长时间去追踪它: typedef union { struct { uint8_t mode: 1; uint8_t texture: 4; uint8_t blend_mode: 2; }; uint8_t key; } RenderKey; 稍后将初始化此联合(在堆栈上): 这似乎表明联合位字段的最后一位不会被初始化。因此,我通过添加未使用的位来修复它: typedef union {

我有一个“臭虫”,我花了很长时间去追踪它:

typedef union {
    struct {
        uint8_t mode: 1;
        uint8_t texture: 4;
        uint8_t blend_mode: 2;
    };
    uint8_t key;    
} RenderKey;
稍后将初始化此联合(在堆栈上):

这似乎表明联合位字段的最后一位不会被初始化。因此,我通过添加未使用的位来修复它:

typedef union {
    struct {
        uint8_t mode: 1;
        uint8_t texture: 4;
        uint8_t blend_mode: 2;
        uint8_t unused: 1;
    };
    uint8_t key;    
} RenderKey;
这是可行的,但我不明白确切的原因。 这个随机1位来自以前堆栈上的随机垃圾,但是为什么C99风格的初始化在这里不起作用呢?因为
联合
和匿名
结构


这发生在
clang3.5
tcc
,但不发生在C11中的
gcc 4.9.2

,§6.7.9中规定

初始化应按初始值设定项列表顺序进行,为特定子对象提供的每个初始值设定项都将覆盖之前为同一子对象列出的任何初始值设定项所有未显式初始化的子对象应隐式初始化,与具有静态存储持续时间的对象相同

但是隐藏的填充位不是子对象,它不受约束,因为从匿名
struct
的角度来看,它不存在,因此编译器没有初始化不是
struct
成员的东西,这一点也不奇怪

类似的例子是

#include <stdio.h>

typedef struct {
    unsigned char foo;
    float value;
} Test;

int main(void) {
    Test test = { .foo = 'a', .value = 1.2f};

    printf("We expect 8 bytes: %zu\n", sizeof(Test));
    printf("We expect 0: %zu\n", (void*)&test.foo - (void*)&test);
    printf("We expect 4: %zu\n", (void*)&test.value - (void*)&test);

    unsigned char* test_ptr = (unsigned char*) &test;

    printf("value of 3rd byte: %d\n", test_ptr[2]);
}
#包括
类型定义结构{
未签名的char-foo;
浮动值;
}试验;
内部主(空){
Test Test={.foo='a',.value=1.2f};
printf(“我们期望8个字节:%zu\n”,sizeof(Test));
printf(“我们期望0:%zu\n”,(void*)和test.foo-(void*)和test);
printf(“我们期望4:%zu\n”,(void*)和test.value-(void*)和test);
无符号字符*test_ptr=(无符号字符*)&test;
printf(“第三字节的值:%d\n”,test_ptr[2]);
}

test\u ptr[2]
会是什么?
struct
的两个成员之间有3个字节的填充,它们不是任何子对象的一部分,初始化它们会浪费时间,因为在正常情况下,您无法访问它们。

我可以遵循匿名
struct
只有7位,因此只初始化这些位。使这种情况混淆的是变量
key
在那里,并且它是一个联合体。@JBEUER:您不是通过
key
初始化联合体,而是通过
struct
初始化联合体。因此,有一个
联合体
的事实是无关紧要的。当您选择通过结构初始化整个对象时,您将“限制”
RenderKey
仅被视为
struct
。换句话说,当您初始化
union
时,您将选择要初始化它的变量。如果它是
union{uint8\u t a;uint32\u t b}
,并使用
a
初始化它(并且
b
的24个最高有效位最终将是随机的),那么情况就不会那么混乱了。
#include <stdio.h>

typedef struct {
    unsigned char foo;
    float value;
} Test;

int main(void) {
    Test test = { .foo = 'a', .value = 1.2f};

    printf("We expect 8 bytes: %zu\n", sizeof(Test));
    printf("We expect 0: %zu\n", (void*)&test.foo - (void*)&test);
    printf("We expect 4: %zu\n", (void*)&test.value - (void*)&test);

    unsigned char* test_ptr = (unsigned char*) &test;

    printf("value of 3rd byte: %d\n", test_ptr[2]);
}