I was asked what this syntax means:
char data[32] = {1};
However I can't remember what it does,. but I remember that it's valid.
Can anyone explain its purpose ?
This will create an array of 32 chars. The first element will be 1 and the rest will be set to zero.
If you do not initialize an automatic array (local and not static) at all, the elements of the array may contain garbage values.
#include <stdio.h>
int main(int argc, char **argv)
{
int i;
char data[5];
for (i = 0; i < 5; i++) {
printf("data[%d] = %d\n", i, data[i]);
}
return 0;
}
Output:
data[0] = 72
data[1] = 12
data[2] = -118
data[3] = 51
data[4] = -119
However, if you do initialize it, it will be initialized with the initializers you have specified. If the number of initializers is less than the total number of the elements in the array, the remaining elements will be initialized to 0.
#include <stdio.h>
int main(int argc, char **argv)
{
int i;
char data[5] = {1};
for (i = 0; i < 5; i++) {
printf("data[%d] = %d\n", i, data[i]);
}
return 0;
}
Output:
data[0] = 1
data[1] = 0
data[2] = 0
data[3] = 0
data[4] = 0
It is initialisation. It sets the first element of the array of a value of 1 (^A in the ASCII table I checked) and the remainder to 0 (default).
To state the C99 standard on omitted initializers:
If there are fewer initializers in a brace-enclosed list than there are elements or members
of an aggregate, or fewer characters in a string literal used to initialize an array of known
size than there are elements in the array, the remainder of the aggregate shall be
initialized implicitly the same as objects that have static storage duration.
and:
If an object that has automatic storage duration is not initialized explicitly,
its value is indeterminate. If an object that has static storage duration is
not initialized explicitly, then:
if it has pointer type, it is initialized to a null pointer;
if it has arithmetic type, it is initialized to (positive or unsigned) zero;
if it is an aggregate, every member is initialized (recursively) according to these rules;
if it is a union, the first named member is initialized (recursively) according to these
rules.
And char is an arithmetic type, so the remaining elements of the array will be initialised to zero.
Yes, you recall correctly. Just Google for "C array initialization":
http://www.eskimo.com/~scs/cclass/notes/sx4aa.html
A couple of notes:
Under older, pre-ANSI C compilers, you could not always supply
initializers for "local" arrays inside functions; you could only
initialize "global" arrays, those outside of any function. Those
compilers are now rare, so you shouldn't have to worry about this
distinction any more.
When an array definition includes an initializer, the array
dimension may be omitted, and the compiler will infer the dimension
from the number of initializers
If there are fewer initializers than elements in the array, the
remaining elements are automatically initialized to 0.
Related
The following code works, but is it well defined?
const int N = 8;
int arr[N];
int* ptr = arr;
for(int i=0; i<N; i++) {
std::cout << ptr[i] << "\n";
}
and a second question:
running this code with -O2 optimizations compiled as C++14 http://cpp.sh/7eagy gives me the following output:
1
0
0
0
4196448
0
4196198
0
wherease the following version:
const int N = 8;
int arr[N] = {};
int* ptr = arr;
for(int i=0; i<N; i++) {
std::cout << ptr[i] << "\n";
}
gives
0
0
0
0
0
0
0
0
indicating that without the = {} arr was not zero initialized, but according to https://en.cppreference.com/w/cpp/language/zero_initialization it should be
at least the given example states:
double f[3]; // zero-initialized to three 0.0's
so what's the reason I'm not getting zeros in the first version?
In the first version, you have
int arr[N];
instead of, second version:
int arr[N] = {};
It has nothing to do with the pointer access. The page you link says:
double f[3]; // zero-initialized to three 0.0's
but that is true only for static variables. Yours is a local, non-static, variable (we don't see the full code, but as it is at the same scope as a for, we can infer it). In standardese, it's written as:
For every named variable with static or thread-local storage duration that is not subject to constant initialization, before any other initialization.
is it well defined to cast a static array to a pointer and then incrementing this pointer to access the elements?
Yes, this is well defined.
The following code works, but is it well defined?
No, that code is not well defined.
You default initialise the array which has automatic storage, not static. The values of the trivially constructible elements are indeterminate. You read those indeterminate values. The behaviour of the program is undefined.
so what's the reason I'm not getting zeros in the first version?
Because you didn't zero-initialise the array in the first version.
Jeffrey has given you three quarters of an answer. I'll make it more complete.
The first example you define an array but you don't initialize the values. In the second example, you actually initialize it to zero.
So in the first example, your array contains random values, whatever is sitting on the stack space. And that's why your example is working oddly.
I'd initialize the array and your first example should work fine.
Here is a related C answer that doesn't work (as a zero initializer for a struct) in C++: Initializing a struct to 0. One of the solutions presented is this:
myStruct _m1 = {0};
This works fine in C, but it doesn't work in C++. :( :
error: cannot initialize a member subobject of type 'myScope::MyStruct' with an rvalue of type 'int'`.
How do you zero-initialize a struct in C++?
Related:
Initializing
a struct to 0 in C: Initializing a struct to 0
Update: (an adjacent, but NOT duplicate question which also turns out to be very useful) Initialization with empty curly braces
See also:
[adjacently-related, but is for C-style arrays, not structs] How to initialize all members of an array to the same value?
To the people voting to close this question:
My question is not a duplicate of this other question (Initialization with empty curly braces), as this other question isn't asking about the various ways to initialize a struct in C++ and why the C way doesn't work, rather, they are asking why does the C++ keyword explicit break one of their initialization techniques. Two distinct questions. Not duplicate.
Follow-up question I asked:
Why doesn't initializing a C++ struct to = {0} set all of its members to 0?
Before we start:
Let me point out that a lot of the confusion around this syntax comes because in C and C++ you can use the = {0} syntax to initialize all members of a C-style array to zero! See here: https://en.cppreference.com/w/c/language/array_initialization. This works:
// z has type int[3] and holds all zeroes, as: `{0, 0, 0}`
int z[3] = {0};
But, that syntax does not work the same for structs, which are entirely different animals than C-style arrays.
See also my follow-up question I asked after writing this answer below: Why doesn't initializing a C++ struct to = {0} set all of its members to 0?
Back to the answer:
I figured it out: to get it to compile, just delete the zero:
# does NOT work
myStruct _m1 = {0};
# works!
myStruct _m1 = {};
It now compiles. However, I ran a bunch of tests to check some things in my struct_initialization.cpp file in my eRCaGuy_hello_world repo, and that does NOT initialize all elements of the struct to zero! Rather, it initializes the struct to its default values. To run my tests and see for yourself, clone my repo above and run eRCaGuy_hello_world/cpp/run_struct_initialization.sh.
Assuming you have this struct:
typedef struct
{
int num1 = 100;
int num2 = -100;
int num3;
int num4 = 150;
} data_t;
Note: the typedef above is a carry-over from when I was testing this stuff in C instead of C++ (although the default struct values are not allowed in C, of course). For C++, this is preferred instead:
struct data_t
{
int num1 = 100;
int num2 = -100;
int num3;
int num4 = 150;
};
So please ignore it wherever I unnecessarily use typedef to define the structs below.
Anyway, if I declare one of the above data_t structs, and then do this:
data_t d2 = {};
printf("d2.num1 = %i\nd2.num2 = %i\nd2.num3 = %i\nd2.num4 = %i\n\n",
d2.num1, d2.num2, d2.num3, d2.num4);
...the output will be:
d2.num1 = 100
d2.num2 = -100
d2.num3 = 0
d2.num4 = 150
And I'm not even sure if d2.num3 is zero because it was initialized to zero or because it was left uninitialized, and that memory location happened to contain zero.
As explained here: https://en.cppreference.com/w/cpp/language/zero_initialization, you can also do this:
myStruct _m1{};
In the example above, this code:
data_t d2{};
printf("d2.num1 = %i\nd2.num2 = %i\nd2.num3 = %i\nd2.num4 = %i\n\n",
d2.num1, d2.num2, d2.num3, d2.num4);
...would produce output identical to what I showed above.
Even in cases where setting the struct to = {0} DOES work, such as this:
// Does NOT do what I expected! Only sets the FIRST value in the struct to zero!
// The rest seem to use default values.
data_t d3 = {0};
printf("d3.num1 = %i\nd3.num2 = %i\nd3.num3 = %i\nd3.num4 = %i\n\n",
d3.num1, d3.num2, d3.num3, d3.num4);
...the output is still not what I expected, as it only sets the first value to zero! (I don't understand why):
d3.num1 = 0
d3.num2 = -100
d3.num3 = 0
d3.num4 = 150
On C-style arrays, however (NOT structs), these semantics work fine. Refer to this answer here (How to initialize all members of an array to the same value?). The following lines, therefore, both set all elements of the C-style array to zero when using C++:
uint8_t buffer[100] = {0}; // sets all elements to 0 in C OR C++
uint8_t buffer[100] = {}; // sets all elements to 0 in C++ only (won't compile in C)
So, after much experimentation, it looks like the following several ways are the ONLY ways to zero-initialize a struct, PERIOD. If you know differently, please comment and/or leave your own answer here.
The only ways possible to zero-initialize a struct in C++ are:
Be explicit:
// C-style typedef'ed struct
typedef struct
{
int num1 = 100;
int num2 = -100;
int num3;
int num4 = 150;
} data_t;
// EXPLICITLY set every value to what you want!
data_t d1 = {0, 0, 0, 0};
// OR (using gcc or C++20 only)
data_t d2 = {.num1 = 0, .num2 = 0, .num3 = 0, .num4 = 0};
Use memset() to force all bytes to zero:
data_t d3;
memset(&d3, 0, sizeof(d3));
Set all default values to zero in the first place:
// C-style typedef'ed struct
typedef struct
{
int num1 = 0;
int num2 = 0;
int num3 = 0;
int num4 = 0;
} data_t;
// Set all values to their defaults, which are zero in
// this case
data_t d4 = {};
// OR
data_t d5{}; // same thing as above in C++
// Set the FIRST value only to zero, and all the rest
// to their defaults, which are also zero in this case
data_t d6 = {0};
Write a constructor for the C++ struct
// 1. Using an initializer list
struct data
{
int num1;
int num2;
int num3;
int num4;
data() :
num1(0),
num2(0),
num3(0),
num4(0) {}
};
data d7; // all values are zero
// OR: 2. manually setting the values inside the constructor
struct data
{
int num1;
int num2;
int num3;
int num4;
data()
{
num1 = 0;
num2 = 0;
num3 = 0;
num4 = 0;
}
};
data d8; // all values are zero
Use a struct with no default values, and make your object you create from it static
typedef struct
{
int num1;
int num2;
int num3;
int num4;
} data_t;
// `static` forces a default initialization of zero for each
// value when no other default values are set
static data_t d9;
So, if you have a struct with non-zero default values, and you want to zero all values, you must do it EXPLICITLY! Here are some more ways:
// 1. Have a `constexpr` copy of the struct that you use to
// reset other struct objects. Ex:
struct data
{
int num1 = 1;
int num2 = 7;
int num3 = -10;
int num4 = 55;
};
constexpr data DATA_ALL_ZEROS = {0, 0, 0, 0};
// Now initialize d13 to all zeros using the above `constexpr` struct
// object
data d13 = DATA_ALL_ZEROS;
// OR 2. Use a `zero()` member function to zero the values:
struct data
{
int num1 = 1;
int num2 = 7;
int num3 = -10;
int num4 = 55;
zero()
{
num1 = 0;
num2 = 0;
num3 = 0;
num4 = 0;
}
};
data d14;
d14.zero();
The big take-away here is that NONE of these: data_t d{}, data_t d = {}, and data_t d = {0}, actually set all members of a struct to zero!
data_t d{} sets all values to their defaults defined in the struct.
data_t d = {} also sets all values to their defaults.
And data_t d = {0} sets only the FIRST value to zero, and all other values to their defaults.
SO, BE EXPLICIT!
Note that the above key take-aways I wrote seem to contradict this documentation on cppreference.com, so it has led me to ask this follow-up question listed just below, which has proven VERY helpful to my understanding!
Going further
MOST USEFUL: Follow-up question of mine: Why doesn't initializing a C++ struct to = {0} set all of its members to 0?
References:
VERY USEFUL:
https://en.cppreference.com/w/cpp/language/zero_initialization
https://en.cppreference.com/w/cpp/language/aggregate_initialization
https://en.cppreference.com/w/cpp/language/value_initialization
VERY USEFUL: Initializing all members of an array (not struct) to the same value:
How to initialize all members of an array to the same value?
[gcc only] How to initialize all members of an array to the same value?
https://github.com/ElectricRCAircraftGuy/eRCaGuy_hello_world/blob/master/cpp/struct_initialization.cpp
Clone this repo and run the code yourself with cpp/run_struct_initialization.sh
Related:
Initializing default values in a struct
*****[my own answer, which demonstrate this sort of struct modification/aggregate member reassignment within any function: leds[0] = {10, 20, 30, 40, 50};] Arduino Stack Exchange: Initializing Array of structs
Generically it's not possible. A class may not provide a way to access all members and in those cases the best you can do is value initialize it which will give you a default version of that class.
Objects in C++ are given the ability to control the values of any subobjects within them. As such, C++ has no mechanism that will force zero-initialization onto any object in general.
Objects with no user-provided constructors or default member initializers can undergo zero-initialization in two cases: if the variable is declared static, or if the object is being value-initialized. There are multiple syntaxes that will provoke value initialization of an object, including T(), T{}, and T t = {};, where applicable.
But other than that, if the creator of the type of an object does not want it to be zero-initialized, then you cannot impose that upon the object. You can ask for value-initialization or default-initialization, but whether either of these will invoke zero-initialization depends on the type.
In C++ for types with no constrictor (id est trivially constructible), {} always initializes all bytes to zero, identically the same as { 0 } in C.
PlainOldData pod{};
For types with a constructor, hence not trivially constructable, it makes little sense to initialize all bytes to zero as those objects are meant to control their own state. What you usually want is default initialization, which can usually be done with {}.:
Object obj{};
// or
Object obj;
You can go around this limitation and use memset to clear the memory, but be aware that it will cause a lot of problems with overwriting vtable pointers, et cetera.
memset(&obj, 0, sizeof obj); // dangerous for non-trivial objects
Here is a related C answer that doesn't work (as a zero initializer for a struct) in C++: Initializing a struct to 0. One of the solutions presented is this:
myStruct _m1 = {0};
This works fine in C, but it doesn't work in C++. :( :
error: cannot initialize a member subobject of type 'myScope::MyStruct' with an rvalue of type 'int'`.
How do you zero-initialize a struct in C++?
Related:
Initializing
a struct to 0 in C: Initializing a struct to 0
Update: (an adjacent, but NOT duplicate question which also turns out to be very useful) Initialization with empty curly braces
See also:
[adjacently-related, but is for C-style arrays, not structs] How to initialize all members of an array to the same value?
To the people voting to close this question:
My question is not a duplicate of this other question (Initialization with empty curly braces), as this other question isn't asking about the various ways to initialize a struct in C++ and why the C way doesn't work, rather, they are asking why does the C++ keyword explicit break one of their initialization techniques. Two distinct questions. Not duplicate.
Follow-up question I asked:
Why doesn't initializing a C++ struct to = {0} set all of its members to 0?
Before we start:
Let me point out that a lot of the confusion around this syntax comes because in C and C++ you can use the = {0} syntax to initialize all members of a C-style array to zero! See here: https://en.cppreference.com/w/c/language/array_initialization. This works:
// z has type int[3] and holds all zeroes, as: `{0, 0, 0}`
int z[3] = {0};
But, that syntax does not work the same for structs, which are entirely different animals than C-style arrays.
See also my follow-up question I asked after writing this answer below: Why doesn't initializing a C++ struct to = {0} set all of its members to 0?
Back to the answer:
I figured it out: to get it to compile, just delete the zero:
# does NOT work
myStruct _m1 = {0};
# works!
myStruct _m1 = {};
It now compiles. However, I ran a bunch of tests to check some things in my struct_initialization.cpp file in my eRCaGuy_hello_world repo, and that does NOT initialize all elements of the struct to zero! Rather, it initializes the struct to its default values. To run my tests and see for yourself, clone my repo above and run eRCaGuy_hello_world/cpp/run_struct_initialization.sh.
Assuming you have this struct:
typedef struct
{
int num1 = 100;
int num2 = -100;
int num3;
int num4 = 150;
} data_t;
Note: the typedef above is a carry-over from when I was testing this stuff in C instead of C++ (although the default struct values are not allowed in C, of course). For C++, this is preferred instead:
struct data_t
{
int num1 = 100;
int num2 = -100;
int num3;
int num4 = 150;
};
So please ignore it wherever I unnecessarily use typedef to define the structs below.
Anyway, if I declare one of the above data_t structs, and then do this:
data_t d2 = {};
printf("d2.num1 = %i\nd2.num2 = %i\nd2.num3 = %i\nd2.num4 = %i\n\n",
d2.num1, d2.num2, d2.num3, d2.num4);
...the output will be:
d2.num1 = 100
d2.num2 = -100
d2.num3 = 0
d2.num4 = 150
And I'm not even sure if d2.num3 is zero because it was initialized to zero or because it was left uninitialized, and that memory location happened to contain zero.
As explained here: https://en.cppreference.com/w/cpp/language/zero_initialization, you can also do this:
myStruct _m1{};
In the example above, this code:
data_t d2{};
printf("d2.num1 = %i\nd2.num2 = %i\nd2.num3 = %i\nd2.num4 = %i\n\n",
d2.num1, d2.num2, d2.num3, d2.num4);
...would produce output identical to what I showed above.
Even in cases where setting the struct to = {0} DOES work, such as this:
// Does NOT do what I expected! Only sets the FIRST value in the struct to zero!
// The rest seem to use default values.
data_t d3 = {0};
printf("d3.num1 = %i\nd3.num2 = %i\nd3.num3 = %i\nd3.num4 = %i\n\n",
d3.num1, d3.num2, d3.num3, d3.num4);
...the output is still not what I expected, as it only sets the first value to zero! (I don't understand why):
d3.num1 = 0
d3.num2 = -100
d3.num3 = 0
d3.num4 = 150
On C-style arrays, however (NOT structs), these semantics work fine. Refer to this answer here (How to initialize all members of an array to the same value?). The following lines, therefore, both set all elements of the C-style array to zero when using C++:
uint8_t buffer[100] = {0}; // sets all elements to 0 in C OR C++
uint8_t buffer[100] = {}; // sets all elements to 0 in C++ only (won't compile in C)
So, after much experimentation, it looks like the following several ways are the ONLY ways to zero-initialize a struct, PERIOD. If you know differently, please comment and/or leave your own answer here.
The only ways possible to zero-initialize a struct in C++ are:
Be explicit:
// C-style typedef'ed struct
typedef struct
{
int num1 = 100;
int num2 = -100;
int num3;
int num4 = 150;
} data_t;
// EXPLICITLY set every value to what you want!
data_t d1 = {0, 0, 0, 0};
// OR (using gcc or C++20 only)
data_t d2 = {.num1 = 0, .num2 = 0, .num3 = 0, .num4 = 0};
Use memset() to force all bytes to zero:
data_t d3;
memset(&d3, 0, sizeof(d3));
Set all default values to zero in the first place:
// C-style typedef'ed struct
typedef struct
{
int num1 = 0;
int num2 = 0;
int num3 = 0;
int num4 = 0;
} data_t;
// Set all values to their defaults, which are zero in
// this case
data_t d4 = {};
// OR
data_t d5{}; // same thing as above in C++
// Set the FIRST value only to zero, and all the rest
// to their defaults, which are also zero in this case
data_t d6 = {0};
Write a constructor for the C++ struct
// 1. Using an initializer list
struct data
{
int num1;
int num2;
int num3;
int num4;
data() :
num1(0),
num2(0),
num3(0),
num4(0) {}
};
data d7; // all values are zero
// OR: 2. manually setting the values inside the constructor
struct data
{
int num1;
int num2;
int num3;
int num4;
data()
{
num1 = 0;
num2 = 0;
num3 = 0;
num4 = 0;
}
};
data d8; // all values are zero
Use a struct with no default values, and make your object you create from it static
typedef struct
{
int num1;
int num2;
int num3;
int num4;
} data_t;
// `static` forces a default initialization of zero for each
// value when no other default values are set
static data_t d9;
So, if you have a struct with non-zero default values, and you want to zero all values, you must do it EXPLICITLY! Here are some more ways:
// 1. Have a `constexpr` copy of the struct that you use to
// reset other struct objects. Ex:
struct data
{
int num1 = 1;
int num2 = 7;
int num3 = -10;
int num4 = 55;
};
constexpr data DATA_ALL_ZEROS = {0, 0, 0, 0};
// Now initialize d13 to all zeros using the above `constexpr` struct
// object
data d13 = DATA_ALL_ZEROS;
// OR 2. Use a `zero()` member function to zero the values:
struct data
{
int num1 = 1;
int num2 = 7;
int num3 = -10;
int num4 = 55;
zero()
{
num1 = 0;
num2 = 0;
num3 = 0;
num4 = 0;
}
};
data d14;
d14.zero();
The big take-away here is that NONE of these: data_t d{}, data_t d = {}, and data_t d = {0}, actually set all members of a struct to zero!
data_t d{} sets all values to their defaults defined in the struct.
data_t d = {} also sets all values to their defaults.
And data_t d = {0} sets only the FIRST value to zero, and all other values to their defaults.
SO, BE EXPLICIT!
Note that the above key take-aways I wrote seem to contradict this documentation on cppreference.com, so it has led me to ask this follow-up question listed just below, which has proven VERY helpful to my understanding!
Going further
MOST USEFUL: Follow-up question of mine: Why doesn't initializing a C++ struct to = {0} set all of its members to 0?
References:
VERY USEFUL:
https://en.cppreference.com/w/cpp/language/zero_initialization
https://en.cppreference.com/w/cpp/language/aggregate_initialization
https://en.cppreference.com/w/cpp/language/value_initialization
VERY USEFUL: Initializing all members of an array (not struct) to the same value:
How to initialize all members of an array to the same value?
[gcc only] How to initialize all members of an array to the same value?
https://github.com/ElectricRCAircraftGuy/eRCaGuy_hello_world/blob/master/cpp/struct_initialization.cpp
Clone this repo and run the code yourself with cpp/run_struct_initialization.sh
Related:
Initializing default values in a struct
*****[my own answer, which demonstrate this sort of struct modification/aggregate member reassignment within any function: leds[0] = {10, 20, 30, 40, 50};] Arduino Stack Exchange: Initializing Array of structs
Generically it's not possible. A class may not provide a way to access all members and in those cases the best you can do is value initialize it which will give you a default version of that class.
Objects in C++ are given the ability to control the values of any subobjects within them. As such, C++ has no mechanism that will force zero-initialization onto any object in general.
Objects with no user-provided constructors or default member initializers can undergo zero-initialization in two cases: if the variable is declared static, or if the object is being value-initialized. There are multiple syntaxes that will provoke value initialization of an object, including T(), T{}, and T t = {};, where applicable.
But other than that, if the creator of the type of an object does not want it to be zero-initialized, then you cannot impose that upon the object. You can ask for value-initialization or default-initialization, but whether either of these will invoke zero-initialization depends on the type.
In C++ for types with no constrictor (id est trivially constructible), {} always initializes all bytes to zero, identically the same as { 0 } in C.
PlainOldData pod{};
For types with a constructor, hence not trivially constructable, it makes little sense to initialize all bytes to zero as those objects are meant to control their own state. What you usually want is default initialization, which can usually be done with {}.:
Object obj{};
// or
Object obj;
You can go around this limitation and use memset to clear the memory, but be aware that it will cause a lot of problems with overwriting vtable pointers, et cetera.
memset(&obj, 0, sizeof obj); // dangerous for non-trivial objects
In the following code, can the value of int be predicted ( how ? ), or it is just the garbage ?
union a
{
int i;
char ch[2];
};
a u;
u.ch[0] = 0;
u.ch[1] = 0;
cout<<u.i;
}
I would say that depends on the size of int and char. A union contains the memory of the largest variable. If int is 4 bytes and char[2] represents 2 bytes, the int consumes more memory than the char-array, so you are not initialising the full int-memory to 0 by setting all char-variables. It depends on your memory initialization mechanisms but basically the value of the int will appear to be random as the extra 2 bytes are filled with unspecified values.
Besides, filling one variable of a union and reading another is exactly what makes unions unsafe in my oppinion.
If you are sure that int is the largest datatype, you can initialize the whole union by writing
union a
{
int i;
char ch[2];
};
void foo()
{
a u = { 0 }; // Initializes the first field in the union
cout << u.i;
}
Therefore it may be a good idea to place the largest type at the beginning of the union. Althugh that doesn't garantuee that all datatypes can be considered zero or empty when all bits are set to 0.
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.
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
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.
Note that an empty aggregate initializer also works:
SHELLEXECUTEINFO sexi = {};
char mytext[100] = {};
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.
{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.
I also use it to initialize strings eg.
char mytext[100] = {0};
It's been awhile since I worked in c/c++ but IIRC, the same shortcut can be used for arrays as well.
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.
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
{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.