在初始化一个对象时{0}是什么意思?

时间:2021-09-14 14:13:42

When {0} is used to initialize an object, what does it mean? I can't find any references to {0} anywhere, and because of the curly braces Google searches are not helpful.

当{0}用于初始化一个对象时,它是什么意思?我在任何地方都找不到任何对{0}的引用,而且由于花括号谷歌搜索没有帮助。

Example code:

示例代码:

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

Without it, the above code will crash on runtime.

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

9 个解决方案

#1


294  

What's happening here is called aggregate initialization. Here is the (abbreviated) definition of an aggregate from section 8.5.1 of the ISO spec:

这里发生的事情叫做聚合初始化。以下是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.

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

Now, using {0} to initialize an aggregate like this is basically a trick to 0 the entire thing. This is because when using aggregate initialization you don't have to specify all the members and the spec requires that all unspecified members be default initialized, which means set to 0 for simple types.

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

Here is the relevant quote from the spec:

以下是说明书中的相关报价:

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:

如果列表中的初始化程序比聚集的成员少,那么每个未显式初始化的成员将被默认初始化。例子:

struct S { int a; char* b; int c; };
S ss = { 1, "asdf" };

initializes ss.a with 1, ss.b with "asdf", and ss.c with the value of an expression of the form int(), that is, 0.

用1初始化ssa,用“asdf”初始化ss.b,用形式int()的表达式的值初始化ss.c,即,0。

You can find the complete spec on this topic here

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

#2


85  

One thing to be aware of is that this technique will not set padding bytes to zero. For example:

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

struct foo
{
    char c;
    int  i;
};

foo a = {0};

Is not the same as:

不等于:

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

In the first case, pad bytes between c and i are uninitialized. Why would you care? Well, if you're saving this data to disk or sending it over a network or whatever, you could have a security issue.

在第一种情况下,c和i之间的填充字节是未初始化的。为什么你会在意吗?如果你把数据保存到磁盘上或者通过网络发送出去,你可能会遇到安全问题。

#3


18  

Note that an empty aggregate initializer also works:

注意,空的聚合初始化器也可以工作:

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

#4


11  

In answer to why ShellExecuteEx() is crashing: your SHELLEXECUTEINFO "sexi" struct has many members and you're only initializing some of them.

为了回答ShellExecuteEx()崩溃的原因:您的SHELLEXECUTEINFO“sexi”struct有许多成员,您只初始化其中的一些成员。

For example, the member sexi.lpDirectory could be pointing anywhere, but ShellExecuteEx() will still try to use it, hence you'll get a memory access violation.

例如,成员sexi。lpDirectory可以指向任何地方,但是ShellExecuteEx()仍然会尝试使用它,因此您将会遇到内存访问违背。

When you include the line:

当你包含这一行时:

SHELLEXECUTEINFO sexi = {0};

before the rest of your structure setup, you're telling the compiler to zero out all structure members before you initialize the specific ones you're interested in. ShellExecuteEx() knows that if sexi.lpDirectory is zero, it should ignore it.

在结构设置的其余部分之前,您要告诉编译器在初始化您感兴趣的特定结构成员之前将所有结构成员归零。ShellExecuteEx()知道如果sexi。lpDirectory是零,它应该忽略它。

#5


7  

I also use it to initialize strings eg.

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

char mytext[100] = {0};

#6


7  

{0} is a valid initializer for any (complete object) type, in both C and C++. It's a common idiom used to initialize an object to zero (read on to see what that means).

{0}是C和c++中任何(完整对象)类型的有效初始化器。这是一个常用的习惯用法,用于将对象初始化为0(请继续阅读以了解这是什么意思)。

For scalar types (arithmetic and pointer types), the braces are unnecessary, but they're explicitly allowed. Quoting the N1570 draft of the ISO C standard, section 6.7.9:

对于标量类型(算术和指针类型),不需要大括号,但是显式地允许使用大括号。引用ISO C标准N1570草案第6.7.9节:

The initializer for a scalar shall be a single expression, optionally enclosed in braces.

标量的初始化器应该是单个表达式,可选地包含在大括号中。

It initializes the object to zero (0 for integers, 0.0 for floating-point, a null pointer for pointers).

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

For non-scalar types (structures, arrays, unions), {0} specifies that the first element of the object is initialized to zero. For structures containing structures, arrays of structures, and so on, this is applied recursively, so the first scalar element is set to the zero, as appropriate for the type. As in any initializer, any elements not specified are set to zero.

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

Intermediate braces ({, }) may be omitted; for example both these are valid and equivalent:

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

int arr[2][2] = { { 1, 2 }, {3, 4} };

int arr[2][2] = { 1, 2, 3, 4 };

which is why you don't have to write, for example, { { 0 } } for a type whose first element is non-scalar.

这就是为什么您不必为第一个元素为非标量的类型编写{{0}}。

So this:

所以这个:

some_type obj = { 0 };

is a shorthand way of initializing obj to zero, meaning that each scalar sub-object of obj is set to 0 if it's an integer, 0.0 if it's floating-point, or a null pointer if it's a pointer.

是将obj初始化为0的一种简写方法,这意味着obj的每个标量子对象都被设置为0,如果是整数,则为0;如果是浮点数,则为0;如果是指针,则为0。

The rules are similar for C++.

c++的规则类似。

In your particular case, since you're assigning values to sexi.cbSize and so forth, it's clear that SHELLEXECUTEINFO is a struct or class type (or possibly a union, but probably not), so not all of this applies, but as I said { 0 } is a common idiom that can be used in more general situations.

在你的特殊情况下,因为你给sexi赋值。cbSize等等,显然SHELLEXECUTEINFO是一个struct或类类型(或者可能是一个联合,但可能不是),所以并不是所有这些都适用,但是正如我所说,{0}是一个常见的习语,可以在更一般的情况下使用。

This is not (necessarily) equivalent to using memset to set the object's representation to all-bits-zero. Neither floating-point 0.0 nor a null pointer is necessarily represented as all-bits-zero, and a { 0 } initializer doesn't necessarily set padding bytes to any particular value. On most systems, though, it's likely to have the same effect.

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

#7


3  

It's been awhile since I worked in c/c++ but IIRC, the same shortcut can be used for arrays as well.

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

#8


2  

I have always wondered, why you should use something like

我一直在想,你为什么要用类似的东西

struct foo bar = { 0 };

Here is a test case to explain:

这里有一个测试用例来解释:

check.c

check.c

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

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

I compile with gcc -O2 -o check check.c and then output the symbol table with readelf -s check | sort -k 2 (this is with gcc 4.6.3 on ubuntu 12.04.2 on a x64 system). Excerpt:

我用gcc -O2 -o校验来编译。c,然后输出带有readelf -s的符号表,检查|排序- k2(这是在ubuntu12.04.2和x64系统上使用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

The important part here is, that my_zero_struct is after __bss_start. The ".bss" section in a C program is the section of memory which is set to zero before main is called see wikipedia on .bss.

这里的重要部分是,my_zero_struct在__bss_start之后。”。C程序中的“bss”段是在main被调用之前被设置为0的内存段。

If you change the code above to:

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

} my_zero_struct = { 0 };

Then the resulting "check" executable looks exactly the same at least with the gcc 4.6.3 compiler on ubuntu 12.04.2; the my_zero_struct is still in the .bss section and thus it will be automatically initialized to zero, before main is called.

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

Hints in the comments, that a memset might initialize the "full" structure is also not an improvement, because the .bss section is cleared fully which also means the "full" structure is set to zero.

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

It might be that the C language standard does not mention any of this, but in a real world C compiler I have never seen a different behaviour.

也许C语言标准没有提到这些,但是在现实的C编译器中,我从来没有见过不同的行为。

#9


-4  

{0} is an anonymous array containing its element as 0.

{0}是一个匿名数组,其元素为0。

This is used to initialize one or all elements of array with 0.

它用于用0初始化数组的一个或所有元素。

e.g. int arr[8] = {0};

例如,int arr[8] = {0};

In this case all the elements of arr will be initialized as 0.

在这种情况下,arr的所有元素都将初始化为0。

#1


294  

What's happening here is called aggregate initialization. Here is the (abbreviated) definition of an aggregate from section 8.5.1 of the ISO spec:

这里发生的事情叫做聚合初始化。以下是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.

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

Now, using {0} to initialize an aggregate like this is basically a trick to 0 the entire thing. This is because when using aggregate initialization you don't have to specify all the members and the spec requires that all unspecified members be default initialized, which means set to 0 for simple types.

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

Here is the relevant quote from the spec:

以下是说明书中的相关报价:

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:

如果列表中的初始化程序比聚集的成员少,那么每个未显式初始化的成员将被默认初始化。例子:

struct S { int a; char* b; int c; };
S ss = { 1, "asdf" };

initializes ss.a with 1, ss.b with "asdf", and ss.c with the value of an expression of the form int(), that is, 0.

用1初始化ssa,用“asdf”初始化ss.b,用形式int()的表达式的值初始化ss.c,即,0。

You can find the complete spec on this topic here

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

#2


85  

One thing to be aware of is that this technique will not set padding bytes to zero. For example:

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

struct foo
{
    char c;
    int  i;
};

foo a = {0};

Is not the same as:

不等于:

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

In the first case, pad bytes between c and i are uninitialized. Why would you care? Well, if you're saving this data to disk or sending it over a network or whatever, you could have a security issue.

在第一种情况下,c和i之间的填充字节是未初始化的。为什么你会在意吗?如果你把数据保存到磁盘上或者通过网络发送出去,你可能会遇到安全问题。

#3


18  

Note that an empty aggregate initializer also works:

注意,空的聚合初始化器也可以工作:

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

#4


11  

In answer to why ShellExecuteEx() is crashing: your SHELLEXECUTEINFO "sexi" struct has many members and you're only initializing some of them.

为了回答ShellExecuteEx()崩溃的原因:您的SHELLEXECUTEINFO“sexi”struct有许多成员,您只初始化其中的一些成员。

For example, the member sexi.lpDirectory could be pointing anywhere, but ShellExecuteEx() will still try to use it, hence you'll get a memory access violation.

例如,成员sexi。lpDirectory可以指向任何地方,但是ShellExecuteEx()仍然会尝试使用它,因此您将会遇到内存访问违背。

When you include the line:

当你包含这一行时:

SHELLEXECUTEINFO sexi = {0};

before the rest of your structure setup, you're telling the compiler to zero out all structure members before you initialize the specific ones you're interested in. ShellExecuteEx() knows that if sexi.lpDirectory is zero, it should ignore it.

在结构设置的其余部分之前,您要告诉编译器在初始化您感兴趣的特定结构成员之前将所有结构成员归零。ShellExecuteEx()知道如果sexi。lpDirectory是零,它应该忽略它。

#5


7  

I also use it to initialize strings eg.

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

char mytext[100] = {0};

#6


7  

{0} is a valid initializer for any (complete object) type, in both C and C++. It's a common idiom used to initialize an object to zero (read on to see what that means).

{0}是C和c++中任何(完整对象)类型的有效初始化器。这是一个常用的习惯用法,用于将对象初始化为0(请继续阅读以了解这是什么意思)。

For scalar types (arithmetic and pointer types), the braces are unnecessary, but they're explicitly allowed. Quoting the N1570 draft of the ISO C standard, section 6.7.9:

对于标量类型(算术和指针类型),不需要大括号,但是显式地允许使用大括号。引用ISO C标准N1570草案第6.7.9节:

The initializer for a scalar shall be a single expression, optionally enclosed in braces.

标量的初始化器应该是单个表达式,可选地包含在大括号中。

It initializes the object to zero (0 for integers, 0.0 for floating-point, a null pointer for pointers).

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

For non-scalar types (structures, arrays, unions), {0} specifies that the first element of the object is initialized to zero. For structures containing structures, arrays of structures, and so on, this is applied recursively, so the first scalar element is set to the zero, as appropriate for the type. As in any initializer, any elements not specified are set to zero.

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

Intermediate braces ({, }) may be omitted; for example both these are valid and equivalent:

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

int arr[2][2] = { { 1, 2 }, {3, 4} };

int arr[2][2] = { 1, 2, 3, 4 };

which is why you don't have to write, for example, { { 0 } } for a type whose first element is non-scalar.

这就是为什么您不必为第一个元素为非标量的类型编写{{0}}。

So this:

所以这个:

some_type obj = { 0 };

is a shorthand way of initializing obj to zero, meaning that each scalar sub-object of obj is set to 0 if it's an integer, 0.0 if it's floating-point, or a null pointer if it's a pointer.

是将obj初始化为0的一种简写方法,这意味着obj的每个标量子对象都被设置为0,如果是整数,则为0;如果是浮点数,则为0;如果是指针,则为0。

The rules are similar for C++.

c++的规则类似。

In your particular case, since you're assigning values to sexi.cbSize and so forth, it's clear that SHELLEXECUTEINFO is a struct or class type (or possibly a union, but probably not), so not all of this applies, but as I said { 0 } is a common idiom that can be used in more general situations.

在你的特殊情况下,因为你给sexi赋值。cbSize等等,显然SHELLEXECUTEINFO是一个struct或类类型(或者可能是一个联合,但可能不是),所以并不是所有这些都适用,但是正如我所说,{0}是一个常见的习语,可以在更一般的情况下使用。

This is not (necessarily) equivalent to using memset to set the object's representation to all-bits-zero. Neither floating-point 0.0 nor a null pointer is necessarily represented as all-bits-zero, and a { 0 } initializer doesn't necessarily set padding bytes to any particular value. On most systems, though, it's likely to have the same effect.

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

#7


3  

It's been awhile since I worked in c/c++ but IIRC, the same shortcut can be used for arrays as well.

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

#8


2  

I have always wondered, why you should use something like

我一直在想,你为什么要用类似的东西

struct foo bar = { 0 };

Here is a test case to explain:

这里有一个测试用例来解释:

check.c

check.c

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

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

I compile with gcc -O2 -o check check.c and then output the symbol table with readelf -s check | sort -k 2 (this is with gcc 4.6.3 on ubuntu 12.04.2 on a x64 system). Excerpt:

我用gcc -O2 -o校验来编译。c,然后输出带有readelf -s的符号表,检查|排序- k2(这是在ubuntu12.04.2和x64系统上使用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

The important part here is, that my_zero_struct is after __bss_start. The ".bss" section in a C program is the section of memory which is set to zero before main is called see wikipedia on .bss.

这里的重要部分是,my_zero_struct在__bss_start之后。”。C程序中的“bss”段是在main被调用之前被设置为0的内存段。

If you change the code above to:

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

} my_zero_struct = { 0 };

Then the resulting "check" executable looks exactly the same at least with the gcc 4.6.3 compiler on ubuntu 12.04.2; the my_zero_struct is still in the .bss section and thus it will be automatically initialized to zero, before main is called.

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

Hints in the comments, that a memset might initialize the "full" structure is also not an improvement, because the .bss section is cleared fully which also means the "full" structure is set to zero.

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

It might be that the C language standard does not mention any of this, but in a real world C compiler I have never seen a different behaviour.

也许C语言标准没有提到这些,但是在现实的C编译器中,我从来没有见过不同的行为。

#9


-4  

{0} is an anonymous array containing its element as 0.

{0}是一个匿名数组,其元素为0。

This is used to initialize one or all elements of array with 0.

它用于用0初始化数组的一个或所有元素。

e.g. int arr[8] = {0};

例如,int arr[8] = {0};

In this case all the elements of arr will be initialized as 0.

在这种情况下,arr的所有元素都将初始化为0。