What does {0} mean when initializing an object?

C++C

C++ Problem Overview


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.

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.

C++ Solutions


Solution 1 - C++

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:

> 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.

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.

You can find the complete spec on this topic here

Solution 2 - C++

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.

Solution 3 - C++

Note that an empty aggregate initializer also works:

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

Solution 4 - C++

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

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.

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.

Solution 5 - C++

{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).

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:

> 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).

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.

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.

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.

The rules are similar for 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.

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.

Solution 6 - C++

I also use it to initialize strings eg.

char mytext[100] = {0};

Solution 7 - C++

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

Solution 8 - C++

I have always wondered, why you should use something like

struct foo bar = { 0 };

Here is a test case to explain:

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:

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.

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.

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.

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.

Solution 9 - C++

It's syntatic sugar to initialize your entire structure to empty/zero/null values.

Long version

SHELLEXECUTEINFO sexi;
sexi.cbSize = 0;
sexi.fMask = 0;
sexi.hwnd = NULL;
sexi.lpVerb = NULL;
sexi.lpFile = NULL;
sexi.lpParameters = NULL;
sexi.lpDirectory = NULL;
sexi.nShow = nShow;
sexi.hInstApp = 0;
sexi.lpIDList = NULL;
sexi.lpClass = NULL;
sexi.hkeyClass = 0;
sexi.dwHotKey = 0;
sexi.hMonitor = 0;
sexi.hProcess = 0;

Short version

SHELLEXECUTEINFO sexi = {0};

Wasn't that much easier?

It's also nice because:

  • you don't have to hunt down every member and initialize it

  • you don't have to worry that you might not initialize new members when they're added later

  • you don't have have to call ZeroMemory

Solution 10 - C++

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

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

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

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

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionMahmoud Al-QudsiView Question on Stackoverflow
Solution 1 - C++Don NeufeldView Answer on Stackoverflow
Solution 2 - C++Harold EkstromView Answer on Stackoverflow
Solution 3 - C++dalleView Answer on Stackoverflow
Solution 4 - C++snowcrash09View Answer on Stackoverflow
Solution 5 - C++Keith ThompsonView Answer on Stackoverflow
Solution 6 - C++Adam PierceView Answer on Stackoverflow
Solution 7 - C++µBioView Answer on Stackoverflow
Solution 8 - C++Ingo BlackmanView Answer on Stackoverflow
Solution 9 - C++Ian BoydView Answer on Stackoverflow
Solution 10 - C++nitin prajapatiView Answer on Stackoverflow