根据当前的 C 标准,分配给已声明但未定义的 `int` 的默认值是多少?

According to the current C Standard, what is the default value assigned to an `int` which is declared but not defined?

C标准问题

简单的问题,但似乎无法通过 duckduckgo 或搜索 SO(此处)找到答案。

我知道在 C 中,标准规定未初始化的 int 数组会导致未定义的行为。 (或者至少大多数编译器都是这样的。)

int a[100]; // 100 x 32bits on stack, values are whatever was left over on the stack
printf("a[5]=%d", a[5]); // undefined behaviour, can be any valid `int` value (-2**15 to 2**15 - 1)

但是,单个int的默认值是多少?

int 一个; printf("a=%d", a);

我的猜测是,因为它在堆栈上,所以 CPU 必须执行“压栈”指令,并且该指令必须取一个值,并且对于 a 最合理的值如果未指定值,则使用的编译器将为零。

我说得对吗?

示例测试程序和反汇编

#include <stdio.h>

int a;
    
int main(void)
{
    printf("%d\n", a);
    return 0;
}

这是这个反汇编:(`gcc -save-temps -Wall test.c -o test)

    .file   "test.c"
    .text
    .globl  a
    .bss
    .align 4
    .type   a, @object
    .size   a, 4
a:
    .zero   4
    .section    .rodata
.LC0:
    .string "%d\n"
    .text
    .globl  main
    .type   main, @function
main:
.LFB0:
    .cfi_startproc
    pushq   %rbp
    .cfi_def_cfa_offset 16
    .cfi_offset 6, -16
    movq    %rsp, %rbp
    .cfi_def_cfa_register 6
    movl    a(%rip), %eax
    movl    %eax, %esi
    leaq    .LC0(%rip), %rdi
    movl    [=12=], %eax
    call    printf@PLT
    movl    [=12=], %eax
    popq    %rbp
    .cfi_def_cfa 7, 8
    ret
    .cfi_endproc
.LFE0:
    .size   main, .-main
    .ident  "GCC: (Debian 10.2.1-6) 10.2.1 20210110"
    .section    .note.GNU-stack,"",@progbits

这似乎有行

a:
    .zero 4

这是否意味着a在.data部分被初始化为4x0x00(字节)的内存块?

在你的例子中

#include <stdio.h>

int a;
    
int main(void)
{
    printf("%d\n", a);
    return 0;
}

变量a是全局声明的,所以初始化为0。

另一方面,如果变量 a 是局部非静态声明的

#include <stdio.h>
    
int main(void)
{
    int a;
    printf("%d\n", a);
    return 0;
}

它有一个不确定的值,使用该值会调用 未定义的行为

引自N1570 6.7.9 初始化 10:

If an object that has automatic storage duration is not initialized explicitly, its value is
indeterminate. If an object that has static or thread storage duration is not initialized
explicitly, then:
— if it has pointer type, it is initialized to a null pointer;
— if it has arithmetic type, it is initialized to (positive or unsigned) zero;
— if it is an aggregate, every member is initialized (recursively) according to these rules,
and any padding is initialized to zero bits;
— if it is a union, the first named member is initialized (recursively) according to these
rules, and any padding is initialized to zero bits;