it-swarm.cn

初始化对象时{0}意味着什么?

{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);
}

没有它,上面的代码将在运行时崩溃。

246
Mahmoud Al-Qudsi

这里发生的事情称为aggregate初始化。以下是ISO规范第8.5.1节中聚合的(缩写)定义:

聚合是一个数组或类,没有用户声明的构造函数,没有私有或受保护的非静态数据成员,没有基类,也没有虚函数。

现在,使用{0}初始化这样的聚合基本上是0整个事情的一个技巧。这是因为当使用聚合初始化您不必指定所有成员并且规范要求所有未指定的成员都是默认初始化的,这意味着对于简单类型设置为0

以下是规范的相关引用:

如果列表中的初始值设定项少于聚合中的成员,则未明确初始化的每个成员都应默认初始化。例:

__码__

使用struct S { int a; char* b; int c; }; S ss = { 1, "asdf" }; 初始化ss.a,使用1初始化ss.b,使用int()形式的表达式的值"asdf"初始化ss.c,即0

你可以找到关于这个主题的完整规范 这里

297
Don Neufeld

需要注意的一点是,这种技术不会将填充字节设置为零。例如:

struct foo
{
    char c;
    int  i;
};

foo a = {0};

不一样:

foo a;
memset(&a,0,sizeof(a));

在第一种情况下,c和i之间的填充字节是未初始化的。你为什么要关心?好吧,如果您将此数据保存到磁盘或通过网络或其他任何方式发送,则可能存在安全问题。

87
Harold Ekstrom

请注意,空聚合初始化程序也有效:

SHELLEXECUTEINFO sexi = {};
char mytext[100] = {};
19
dalle

回答为什么ShellExecuteEx()崩溃:你的SHELLEXECUTEINFO“sexi”结构有很多成员,你只是初始化其中的一些。

例如,成员sexi.lpDirectory可能指向任何位置,但ShellExecuteEx()仍将尝试使用它,因此您将获得内存访问冲突。

当您包含该行时:

SHELLEXECUTEINFO sexi = {0};

在你的结构设置的其余部分之前,你告诉编译器在初始化你感兴趣的特定成员之前将 all structure成员清零.ShellExecuteEx()知道如果sexi.lpDirectory为零,它应该忽略它。

11
snowcrash09

我也用它来初始化字符串,例如。

char mytext[100] = {0};
7
Adam Pierce

{0}是C和C++中任何(完整对象)类型的有效初始值设定项。这是用于将对象初始化为(读取以查看其含义)的常用习惯用法。

对于标量类型(算术和指针类型),大括号是不必要的,但它们是明确允许的。引用 N1570草案 ISO C标准,第6.7.9节:

标量的初始值设定项应为单个表达式,可选择用大括号括起来。

它将对象初始化为零(0表示整数,0.0表示浮点数,空指针表示指针)。

对于非标量类型(结构,数组,联合),{0}指定对象的 first 元素初始化为零。对于包含结构,结构数组等的结构,这是递归应用的,因此第一个标量元素设置为零,适用于类型。与任何初始化程序一样,未指定的任何元素都设置为零。

中间括号({})可以省略;例如,这些都是有效的和等效的:

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 }是一种常见的习语,可以在更一般的情况下使用。

这是 not (必然)等效于使用memset将对象的表示设置为all-bits-zero。浮点0.0和空指针都不一定表示为全位零,而{ 0 }初始化器不一定将填充字节设置为任何特定值。但是,在大多数系统中,它可能会产生相同的效果。

7
Keith Thompson

自从我在c/c ++工作但是IIRC以来已经有一段时间了,同样的快捷方式也可以用于数组。

3
µBio

我一直想知道, 为什么 你应该使用类似的东西

struct foo bar = { 0 };

这是一个测试用例来解释:

check.c

struct f {
    int x;
    char a;
} my_zero_struct;

int main(void)
{
    return my_zero_struct.x;
}

我使用gcc -O2 -o check check.c进行编译,然后使用readelf -s check | sort -k 2输出符号表(这是在x64系统上的ubuntu 12.04.2上的gcc 4.6.3)。摘抄:

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

这里的重要部分是my_zero_struct位于__bss_start之后。 C程序中的“.bss”部分是内存的一部分,设置为零 之前 main被称为。 wikipedia on .bss

如果您将上面的代码更改为:

} my_zero_struct = { 0 };

然后生成的“check”可执行文件看起来 完全 至少与ubuntu 12.04.2上的gcc 4.6.3编译器相同; my_zero_struct仍然在.bss部分,因此在调用main之前它将自动初始化为零。

注释中的提示,即memset可能初始化“完整”结构也不是一种改进,因为.bss部分被完全清除,这也意味着“完整”结构被设置为零。

可能 是C语言标准没有提到任何这个,但在现实世界的C编译器中我从未见过不同的行为。

2
Ingo Blackman