在C语言中静态变量的初始化

46

我有一个关于C语言中静态变量初始化的问题。我知道如果我们声明一个全局的静态变量,默认值是0。例如:

static int a; //although we do not initialize it, the value of a is 0

但是以下数据结构怎么办:

typedef struct
{
    int a;
    int b;
    int c;
} Hello;

static Hello hello[3];

hello[0]hello[1]hello[2] 结构体中的所有成员都被初始化为 0 吗?

5个回答

66

是的,所有具有静态存储的对象都会被初始化。请参见C99标准(PDF文档)中的6.7.8/10。

如果没有明确初始化自动存储期的对象,则其值是不确定的。如果没有明确初始化具有静态存储期的对象,则:
- 如果它具有指针类型,则将其初始化为null指针;
- 如果它具有算术类型,则将其初始化为(正或无符号的)零;
- 如果它是一个聚合体,则根据这些规则递归地初始化每个成员;
- 如果它是一个联合体,则根据这些规则递归地初始化第一个命名成员。

为了初始化对象中的所有内容,无论它是static还是不是,我喜欢使用通用零初始化器。

sometype identifier0 = {0};
someothertype identifier1[SOMESIZE] = {0};
anytype identifier2[SIZE1][SIZE2][SIZE3] = {0};

在C语言中,不存在“部分初始化”的概念。一个对象要么是完全初始化的(在没有其他值的情况下为正确类型的0),要么根本没有被初始化。
如果你想进行部分初始化,那么就不能一开始就进行初始化。
int a[2]; // uninitialized
int b[2] = {42}; // b[0] == 42; b[1] == 0;
a[0] = -1; // reading a[1] invokes UB

1
你能否解释一下这行代码的意思?a[0] = -1; - lfalkau
2
这是一个简单的赋值。在定义变量 a(并未初始化)后,读取 a[0]a[1] 将会导致未定义行为。在对 a[0] 进行赋值之后,您可以安全地从中读取,但不能从 a[1] 中读取。 - pmg
"UB"是什么意思? - undefined
UB 是指未定义行为。请参考,例如,https://stackoverflow.com/questions/2397984/undefined-unspecified-and-implementation-defined-behavior - undefined

3
是的,只要它们具有静态或线程存储持续时间,它们就是已经初始化的。
C11(n1570),§6.7.9 初始化#10
如果具有静态或线程存储持续时间的对象没有明确初始化,则:
[...]
- 如果它具有算术类型,则初始化为(正数或无符号)零; - 如果它是一个聚合体,则每个成员都按照这些规则进行递归初始化,并且任何填充都初始化为零位;
[...]

1
C11标准的草案(PDF文档)可以在网上免费获取。 - pmg
所有具有静态存储期的对象在程序启动之前必须进行初始化(设置为其初始值)。这是c99 pdf中的5.1.2.2.2规定。这回答了我半相关问题。如果您使用静态变量因为您希望它在函数调用之间保留其值(例如用于运行总数),那么您需要手动将其初始化为0吗?不需要。 - Alan Corey

2
是的,文件作用域的静态变量都被初始化为零,包括结构体、数组等所有成员。
参考this question(我也会投票将此关闭为重复问题)。
编辑:这个问题得到了更好的答案,因此我投票将那个问题作为重复的关闭,并转而关注于这个问题。
供参考,这是从那个问题的被接受答案中提取出来的C FAQ link,当然这里链接的C99和C11标准是权威的。

1

我要补充的是静态变量(或数组)被分为两种类型。

初始化是从编译时的代码中获得值的那些。这些通常存储在 DS 中,尽管这取决于编译器。

另一种类型是未初始化的静态变量,它们在运行时进行初始化,并存储到 BSS 段中,虽然这也取决于编译器。

BSS


0

对于那些不想阅读标准的人,https://en.cppreference.com/w/c/language/initialization 中也提到了:

隐式初始化

如果没有提供初始化程序:

  • 具有自动存储期的对象将被初始化为不确定值(可能是陷阱表示)
  • 具有静态和线程本地存储期的对象将被零初始化

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接