何时{0}
用于初始化对象,这是什么意思?我找不到任何{0}
地方的任何引用,并且由于大括号,谷歌搜索没有帮助.
示例代码:
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节中聚合的(缩写)定义:
聚合是一个数组或类,没有用户声明的构造函数,没有私有或受保护的非静态数据成员,没有基类,也没有虚函数.
现在,使用{0}
像这样初始化聚合基本上是0
整个事情的一个技巧.这是因为在使用聚合初始化时,您不必指定所有成员,并且规范要求默认初始化所有未指定的成员,这意味着设置0
为简单类型.
以下是规范的相关引用:
如果列表中的初始值设定项少于聚合中的成员,则未明确初始化的每个成员都应默认初始化.例:
struct S { int a; char* b; int c; }; S ss = { 1, "asdf" };初始化
ss.a
with1
,ss.b
with"asdf"
和ss.c
with表达式的表达式int()
,即0
.
您可以在此处找到有关此主题的完整规范
需要注意的一点是,这种技术不会将填充字节设置为零.例如:
struct foo { char c; int i; }; foo a = {0};
不一样:
foo a; memset(&a,0,sizeof(a));
在第一种情况下,c和i之间的填充字节是未初始化的.你为什么要关心?好吧,如果您将此数据保存到磁盘或通过网络或其他任何方式发送,则可能存在安全问题.
请注意,空聚合初始化程序也有效:
SHELLEXECUTEINFO sexi = {}; char mytext[100] = {};
回答为什么ShellExecuteEx()
崩溃:你的SHELLEXECUTEINFO
"sexi"结构有很多成员,你只是初始化其中的一些.
例如,成员sexi.lpDirectory
可能指向任何位置,但ShellExecuteEx()
仍会尝试使用它,因此您将获得内存访问冲突.
当您包含该行时:
SHELLEXECUTEINFO sexi = {0};
在你的结构设置的其余部分之前,你告诉编译器在你初始化你感兴趣的特定结构之前将所有结构成员清零.ShellExecuteEx()
知道如果sexi.lpDirectory
为零,它应该忽略它.
我也用它来初始化字符串,例如.
char mytext[100] = {0};
{0}
是C和C++中任何(完整对象)类型的有效初始值设定项.这是用于将对象初始化为零的常用习惯用法(请继续阅读以了解其含义).
对于标量类型(算术和指针类型),大括号是不必要的,但它们是明确允许的.引用ISO C标准的N1570草案,第6.7.9节:
标量的初始值设定项应为单个表达式,可选择用大括号括起来.
它将对象初始化为零(0
对于整数,0.0
对于浮点,指针的空指针).
对于非标量类型(结构,数组,联合),{0}
指定将对象的第一个元素初始化为零.对于包含结构,结构数组等的结构,这是递归应用的,因此第一个标量元素设置为零,适用于类型.与任何初始化程序一样,未指定的任何元素都设置为零.
中间括号({
,}
)可以省略; 例如,这些都是有效的和等效的:
int arr[2][2] = { { 1, 2 }, {3, 4} }; int arr[2][2] = { 1, 2, 3, 4 };
这就是为什么你不必编写例如{ { 0 } }
第一个元素是非标量的类型的原因.
所以这:
some_type obj = { 0 };
是一种初始化obj
为零的简写方式,这意味着如果每个标量子对象obj
是0
一个整数(0.0
如果它是浮点数),则设置为每个标量子对象,如果它是一个指针,则设置为空指针.
C++的规则类似.
在您的特定情况下,由于您要将值分配给sexi.cbSize
等等,很明显它SHELLEXECUTEINFO
是一个结构或类类型(或者可能是一个联合,但可能不是),所以并非所有这些都适用,但正如我所说的那样{ 0 }
是常见的可以在更一般的情况下使用的习语.
这不一定(必然)等同于使用memset
将对象的表示设置为all-bits-zero.浮点0.0
和空指针都不一定表示为全比特零,并且{ 0 }
初始化器不一定将填充字节设置为任何特定值.但是,在大多数系统中,它可能会产生相同的效果.