这在一定程度上取决于您放置相应变量定义的位置,而且似乎也取决于使用的编译器。
自动存储时长
让我们讨论一下变量具有自动存储持续时间时的区别(如果您将它放在函数或块范围内并且没有static关键字):
void someFunction() {
variable_t my_variable; // (1)
variable_t my_variable = {}; // (2)
}
(1) 表示没有显式初始化的变量定义。而根据这个online C standard draft,它的价值是不确定的:
如果具有自动存储持续时间的对象未初始化
明确地说,它的值是不确定的。
(2) 是一个变量定义,通过没有指示符的初始化器列表进行显式初始化,即不通过成员的名称将值与成员关联,而仅通过值的顺序(参见6.7.9 p17..21)。
有趣的段落是6.7.9 p21,它指出如果初始化列表的条目少于结构成员的数量,则根据静态存储持续时间的初始化规则对成员进行初始化(即0或@987654330 @ 后面会解释):
如果大括号括起来的列表中的初始值设定项比那里少
是聚合的元素或成员,...,其余的
聚合应隐式初始化,与对象相同
具有静态存储持续时间。
所以看起来如果你写variable_t my_variable = {},那么所有的成员都会被初始化为0或者NULL。
然而,正如 aschepler 在 cmets 中提到的,C initialization list grammar 声明初始化列表不能为空(另请参见 cppreference.com):
...初始化器必须是非空的,用大括号括起来的,
成员的初始值设定项的逗号分隔列表
所以根据标准,C 中的初始化列表至少需要一个条目;在我的 XCode8.3 环境中使用-std=gnu99 对其进行测试时,似乎支持一个空的初始化列表,但我知道这不是一个有效的参考。所以为了安全起见,不依赖于特定的编译器扩展,你实际上应该这样写:
variable_t my_variable = {0};
静态存储时长
在文件范围内,您的变量定义将具有静态存储持续时间,然后应用其他规则(参见6.7.9 (10)):
(10) ... 如果具有静态或线程存储持续时间的对象是
未显式初始化,则:
- 如果有指针类型,则初始化为空指针;
- 如果它具有算术类型,则将其初始化为(正或无符号)零;
- 如果是聚合,则每个成员都根据这些规则进行初始化(递归),并且任何填充都初始化为零位;
- 如果是联合,则根据这些规则(递归)初始化第一个命名成员,并初始化任何填充
零位;
...
(21) 如果大括号括起来的列表中的初始值设定项少于聚合的元素或成员,...聚合的其余部分应被隐式初始化,与具有静态存储持续时间的对象相同。
所以如果你写...
#include <stdio.h>
variable_t my_variable; // (1)
variable_t my_variable = {}; // (2)
那么 (1) 和 (2) 实际上会产生相同的结果,因为对于未显式初始化的变量 (1),适用第 (10) 段,而对于显式但为空的初始化变量 (2),根据第 (21) 段),每个成员都回退到 (10) 的初始化规则。
同样,编译器可能不支持上面讨论的空初始化列表。
希望它有所帮助(因为它已经输入了很多 :-))