What does {0} mean when initializing an object?
当使用
示例代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | SHELLEXECUTEINFO sexi = {0}; // what does this do? sexi.cbSize = sizeof(SHELLEXECUTEINFO); sexi.hwnd = NULL; sexi.fMask = SEE_MASK_NOCLOSEPROCESS; sexi.lpFile = lpFile.c_str(); sexi.lpParameters = args; sexi.nShow = nShow; if(ShellExecuteEx(&sexi)) { DWORD wait = WaitForSingleObject(sexi.hProcess, INFINITE); if(wait == WAIT_OBJECT_0) GetExitCodeProcess(sexi.hProcess, &returnCode); } |
如果没有它,上述代码将在运行时崩溃。
这里发生的事情称为聚合初始化。以下是ISO规范第8.5.1节对集料的(缩写)定义:
An aggregate is an array or a class with no user-declared constructors, no private or protected non-static data members, no base classes, and no virtual functions.
现在,使用
以下是规范中的相关报价:
If there are fewer initializers in the list than there are members in the
aggregate, then each member not
explicitly initialized shall be
default-initialized.
Example:
1
2 struct S { int a; char* b; int c; };
S ss = { 1,"asdf" };initializes
ss.a with1 ,ss.b with
"asdf" , andss.c with the value of an
expression of the formint() , that is,
0 .
您可以在这里找到关于这个主题的完整规范
需要注意的一点是,此技术不会将填充字节设置为零。例如:
1 2 3 4 5 6 7 | struct foo { char c; int i; }; foo a = {0}; |
不同于:
1 2 | foo a; memset(&a,0,sizeof(a)); |
在第一种情况下,C和I之间的pad字节未初始化。你为什么会在意?好吧,如果您将这些数据保存到磁盘上,或者通过网络或其他方式发送,那么您可能会遇到安全问题。
请注意,空聚合初始值设定项也可以工作:
1 2 | SHELLEXECUTEINFO sexi = {}; char mytext[100] = {}; |
回答为什么
例如,成员
当包括行时:
1 | SHELLEXECUTEINFO sexi = {0}; |
在结构设置的其余部分之前,您要告诉编译器在初始化您感兴趣的特定结构成员之前将所有结构成员清零。
EDCOX1·0是任意(完整对象)类型的有效初始化器,在C和C++中都是有效的初始化器。这是一个常用的习惯用法,用于将对象初始化为零(继续阅读以了解这意味着什么)。
对于标量类型(算术和指针类型),大括号是不必要的,但它们是显式允许的。引用ISO C标准第6.7.9节N1570草案:
The initializer for a scalar shall be a single expression, optionally enclosed in braces.
它将对象初始化为零(对于整数为
对于非标量类型(结构、数组、联合),
中间支撑(
1 2 3 | int arr[2][2] = { { 1, 2 }, {3, 4} }; int arr[2][2] = { 1, 2, 3, 4 }; |
这就是为什么您不必为第一个元素为非标量的类型编写
因此:
1 | some_type obj = { 0 }; |
是将
这些规则类似于C++。
在您的特定情况下,由于您要为
这并不(必然)等同于使用
我也用它来初始化字符串。
1 | char mytext[100] = {0}; |
这是一段时间以来,我工作在C/C++ +,但Irc,同样的快捷方式也可以用于数组。
我一直在想,你为什么要用
1 | struct foo bar = { 0 }; |
下面是一个测试案例来解释:
检查C
1 2 3 4 5 6 7 8 9 | struct f { int x; char a; } my_zero_struct; int main(void) { return my_zero_struct.x; } |
我用
1 2 3 4 5 6 7 | 59: 0000000000601018 0 NOTYPE GLOBAL DEFAULT ABS __bss_start 48: 0000000000601018 0 NOTYPE GLOBAL DEFAULT ABS _edata 25: 0000000000601018 0 SECTION LOCAL DEFAULT 25 33: 0000000000601018 1 OBJECT LOCAL DEFAULT 25 completed.6531 34: 0000000000601020 8 OBJECT LOCAL DEFAULT 25 dtor_idx.6533 62: 0000000000601028 8 OBJECT GLOBAL DEFAULT 25 my_zero_struct 57: 0000000000601030 0 NOTYPE GLOBAL DEFAULT ABS _end |
重要的是,
如果将上述代码更改为:
1 | } my_zero_struct = { 0 }; |
然后生成的"check"可执行文件至少与Ubuntu 12.04.2上的GCC 4.6.3编译器看起来完全相同;
注释中的提示是,
可能是C语言标准没有提到任何这一点,但在现实世界中,C编译器从未见过不同的行为。
0是一个匿名数组,其元素为0。
这用于用0初始化数组的一个或所有元素。
例如,int arr[8]=0
在这种情况下,arr的所有元素都将初始化为0。