2013-02-28 53 views
4

从实验(在铛和GCC,与-O2和-O0)是似乎,在下面的代码未提及的结构字段*是否始终被初始化为零(即当结构在堆栈上时)?

typedef struct foo_s { int i; int j; } foo_t; 
int main(void) { 
    foo_t foo = {.i = 42}; 
    ... 

foo.j是自动为零。

是否由C99保证,还是编译器特定的实现细节?

注意:我甚至试图在堆栈下面的无效内存中写入0xFFs,在后面给出的foo地址处。

更新:有几条评论指出,这只是因为堆栈下方的内存碰巧包含零。下面的代码确保不是这种情况,并且可以证明GCC -O0正在调零内存。

-7和-6的偏移量与编译器相关。他们需要在铿锵中有所不同。

typedef struct foo_s { int i; int j; } foo_t; 

int main(void) { 
    int r; 
    int *badstack0 = &r - 7; 
    int *badstack1 = &r - 6; 

    *badstack0 = 0xFF; // write to invalid ram, below stack 
    printf("badstack0 %p, val: %2X\n", badstack0, *badstack0); 
    *badstack1 = 0xEE; // write to invalid ram, below stack 
    printf("badstack1 %p, val: %2X\n", badstack1, *badstack1); 

    // struct test 
    foo_t foo = {.i = 42}; 
    printf("&foo.i %p\n", &foo.i); 
    printf("&foo.j %p\n", &foo.j); 
    printf("struct test: i:%i j:%i\n", foo.i, foo.j); 
    return 0; 
} 

输出:

badstack0 0x7fff221e2e80, val: FF 
badstack1 0x7fff221e2e84, val: EE 
&foo.i 0x7fff221e2e80 
&foo.j 0x7fff221e2e84 
struct test: i:42 j:0 

回答

9

如果你提供任何initialisers,就好像它们是静态的没有明确提及的成员被初始化。这是通过在6.7.9(19)的标准保证:

在初始化列表顺序应发生的初始化,设置用于特定的子对象重写为同一子对象任何前面列出的初始化每个初始化; 所有未明确初始化的子对象都应隐式初始化,它们与具有静态存储持续时间的对象相同。

(重点由我加)

如果不初始化任何成员,所有成员的值是不确定的。

+0

值得一提的是,在特定的情况下,OP在程序的开头只是有一个归零堆栈区域,并且它的'j'成员的值为'0'。 – 2013-02-28 14:45:33

+5

不,即使堆栈区域未被清零,OP也有'foo_t foo = {.i = 42};'明确初始化一个成员。因此,其他成员必须初始化为0,就好像它是一个'static int j;'。 – 2013-02-28 14:52:29

+0

@Daniel Fischer IBM说的相反吗? http://publib.boulder.ibm.com/infocenter/lnxpcomp/v8v101/index.jsp?topic=%2Fcom.ibm.xlcpp8l.doc%2Flanguage%2Fref%2Fstrin.htm“temp_address.postal_code取决于存储类temp_address变量;如果它是静态的,则该值将为NULL。“ – fadedbee 2013-02-28 15:13:26

4

C保证只要至少有一个数组/结构体/联合体*中的至少一个成员被初始化,那么所有其他成员将被初始化,就像他们有静态存储持续时间一样,正如Daniel Fischer的答案中所引用的那样。换句话说,所有其他成员自动设置为零或NULL。

数组/结构体/联合体的存储类型不重要,它们根据相同的规则进行初始化,无论它们是否具有自动或静态存储持续时间。

这不是C99或更高版本独有的东西,C有总是有此要求。所有符合规范的C编译器都遵循此规则,它是规范的而不是实现定义的。

这与“调试版”无关。

由于事实上,这个规则就是为什么你可以通过编写

int array[100] = {0}零整个阵列的解释。

这段代码的意思是“初始化第一个元素为零,然后初始化其余99个元素,就好像它们具有静态存储时间,即使它们为零”。


(*)这三种类型在C标准中正式命名为“聚合类型”。

+0

Daniel Fischer的答案应该被接受为正确答案。我的回答仅在OP编辑后添加了更多详细信息。 – Lundin 2013-02-28 15:16:26

+0

如果工会的第一个成员不是最大的,那么标准对其他成员的初始化进行了什么规定?例如,如果空指针,浮点零和整数零都有不同的32位表示,那么声明'union {void * moe [1];浮动拉里[2]; unsigned char curly [12];} STOOGE = {0};''curly'的前四个字节显然应该包含一个空指针的unsigned char'表示,但其余的呢? – supercat 2013-03-04 17:25:36

+0

@supercat该标准在联合和其他“聚合”类型之间没有区别,参见C11 6.7.9/21。初始化规则递归地应用于所有成员。在你的例子中,第一个数组成员的第一项将显式初始化为一个空指针,然后剩下的所有项目就好像它们具有静态存储持续时间。也就是说,第一个数组的其余部分,然后是所有其他数组成员。一切都将被设置为零。 – Lundin 2013-03-05 07:24:10