Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/72.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 未提及的结构字段*是否总是*初始化为零(即当结构位于堆栈上时)?_C_Struct_Initialization - Fatal编程技术网

C 未提及的结构字段*是否总是*初始化为零(即当结构位于堆栈上时)?

C 未提及的结构字段*是否总是*初始化为零(即当结构位于堆栈上时)?,c,struct,initialization,C,Struct,Initialization,从实验(在Clang和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 更新:有几个评论指出这只是因为堆栈下面的内存恰好包含零。下面的代码确保情况并非如此,

从实验(在Clang和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

如果您提供任何初始值设定项,则未明确提及的成员将被初始化为静态成员。这由6.7.9(19)中的标准保证:

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

(重点由我补充)


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

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

数组/struct/union的存储类型无关紧要,它们根据相同的规则初始化,无论它们是自动存储持续时间还是静态存储持续时间

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

这与“调试版本”调零无关

事实上,这条规则解释了为什么可以通过写入将整个数组归零

int数组[100]={0}

这段代码的意思是,“将第一个元素初始化为零,并将其余99个元素初始化为静态存储持续时间,即将它们也设为零”



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

值得补充的是,在特定情况下,OP只是在程序开始时有一个归零的堆栈区域,并且该区域以
j
成员的值
0
显示。不,即使堆栈区域没有归零,OP有
foo\u t foo={.i=42}一个成员的显式初始化。因此,另一个成员必须初始化为0,就好像它是一个
static int j
@Daniel Fischer IBM的说法正好相反吗?“temp_address.postal_代码取决于temp_address变量的存储类;如果它是静态的,则该值将为NULL。”他们确实说它取决于存储类,但这与标准相矛盾(顺便说一句,C99中的第6.7.8节)。由于
结构
已初始化,因此没有显式初始化器的成员应隐式初始化,与具有静态存储持续时间的对象相同。在IBM站点上的示例中,它是一个指针,因此必须初始化为空指针。我的回答只在OP编辑后添加更多详细信息。如果联盟的第一个成员不是最大的,那么标准对其他成员的初始化有什么规定?例如,如果一个空指针、浮点零和整数零都有不同的32位表示,那么声明
union{void*moe[1];float larry[2];unsigned char curly[12];}STOOGE={0}
显然,
curly
的前四个字节应该包含空指针的
unsigned char
表示,但是其余的呢?@supercat标准对union和其他“聚合”类型没有区别,请参见C11 6.7.9/21。初始化规则递归地应用于所有成员。在您的示例中,第一个数组成员的第一个项将显式初始化为空指针,然后所有项的其余项将被初始化为静态存储持续时间。也就是说,第一个数组的其余项,然后是所有其他数组成员。一切都将设置为零。什么样的零?指针数组是否会被初始化为空指针,而其他所有指针都会被初始化为零位,或者是什么?@supercat它们将被初始化,就好像它们有静态存储持续时间一样。阅读6.7.9/10。