Are Members of a C++ Struct Initialized to 0 by Default

Are members of a C++ struct initialized to 0 by default?

They are not null if you don't initialize the struct.

Snapshot s; // receives no initialization
Snapshot s = {}; // value initializes all members

The second will make all members zero, the first leaves them at unspecified values. Note that it is recursive:

struct Parent { Snapshot s; };
Parent p; // receives no initialization
Parent p = {}; // value initializes all members

The second will make p.s.{x,y} zero. You cannot use these aggregate initializer lists if you've got constructors in your struct. If that is the case, you will have to add proper initalization to those constructors

struct Snapshot {
int x;
double y;
Snapshot():x(0),y(0) { }
// other ctors / functions...
};

Will initialize both x and y to 0. Note that you can use x(), y() to initialize them disregarding of their type: That's then value initialization, and usually yields a proper initial value (0 for int, 0.0 for double, calling the default constructor for user defined types that have user declared constructors, ...). This is important especially if your struct is a template.

How to initialize a struct to 0 in C++

Before we start:

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

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

  1. 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};
  2. Use memset() to force all bytes to zero:

     data_t d3;
    memset(&d3, 0, sizeof(d3));
  3. 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};
  4. 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
  5. 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;
  6. 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!

  1. data_t d{} sets all values to their defaults defined in the struct.
  2. data_t d = {} also sets all values to their defaults.
  3. 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

  1. MOST USEFUL: Follow-up question of mine: Why doesn't initializing a C++ struct to = {0} set all of its members to 0?

References:

  1. VERY USEFUL:
    1. https://en.cppreference.com/w/cpp/language/zero_initialization
    2. https://en.cppreference.com/w/cpp/language/aggregate_initialization
    3. https://en.cppreference.com/w/cpp/language/value_initialization
  2. VERY USEFUL: Initializing all members of an array (not struct) to the same value:
    1. How to initialize all members of an array to the same value?
    2. [gcc only] How to initialize all members of an array to the same value?
  3. https://github.com/ElectricRCAircraftGuy/eRCaGuy_hello_world/blob/master/cpp/struct_initialization.cpp
    1. Clone this repo and run the code yourself with cpp/run_struct_initialization.sh

Related:

  1. Initializing default values in a struct
  2. *****[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

Why doesn't initializing a C++ struct to `= {0}` set all of its members to 0?

So, why doesn't initializing a C++ struct to = {0} set all of its members to 0?

Because you are only providing one value, while the class has more than one member.

When you have T t{}; or T t = {} what you are doing is called value initialization. In value initialization, if the object/member does not have a default constructor, or a default member initializer, then the compiler falls back to zero initializing the objec/member. So with

data_t d{}

the value of the members in order would be 100, -100, 0 ,150 and that 0 for num3 happens because it has no default and you did not provide a value in the {} so the compiler falls back to zero initializing num3. This is the same with data_t d = {}. With data_t d = {0} you provide the first element, so num1 is 0, but then like the first two, all of the other members are initialized with their default value if they have one, or zero initialized if they don't, giving you 0, -100, 0, 150 for the member values.

This was a change that happened when C++11 was released and allowed for default member initializers.


If your data_t was defined like

typedef struct
{
int num1;
int num2;
int num3;
int num4;
} data_t;

then data_t d{}, data_t d = {}, data_t d = {0} would all leave you with a zero initialized class since there are no default member initializers and the only value you provide in you braced-init-list (the technical name for {...}) is zero so all members become zero.

Are the members of a c struct guaranteed to be initialized to 0?

Relevant parts of the C99 standard:

section 6.2.4, §3:

An object whose identifier is declared
with external or internal linkage, or
with the storage-class specifier
static has static storage duration.
Its lifetime is the entire execution
of the program and its stored value is
initialized only once, prior to
program startup.

section 6.2.4, §4:

An object whose identifier is declared
with no linkage and without the
storage-class specifier static has
automatic storage duration.

section 6.2.4, §5 (regarding objects with automatic storage duration):

The initial value of the object is
indeterminate. If an initialization is
specified for the object, it is
performed each time the declaration is
reached in the execution of the block;
otherwise, the value becomes
indeterminate each time the
declaration is reached.

section 6.7.8, §10:

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.

Does standard C accept `{0}` as an initializer for any struct?

Yes, this is perfectly valid.

All scalar types (integer types, floating point types and pointer types) accept 0 as an initialiser. This is not a fundamental property of scalar types, but it happens to apply to all of them.

All aggregate types (arrays and structures) and union types will have at least one member or element. Either the first member or element is a scalar type, or it is another aggregate or union type. If the former, that makes {0} a valid initialiser. If the latter, apply the same logic: that too will have at least one member or element. Either that is a scalar type, or it is another aggregate or union type. Keep going. There is no way to have infinitely nested structures, so you'll always end up at a scalar type.

Non-standard language extensions could invalidate some of these assumptions. For instance, a language extension could define strongly-typed enumeration types which do not accept 0 as an initialiser, or empty structures, or zero-length arrays.

Are uninitialized struct members always set to zero?

item 8.5.1.7 of standard draft:

-7- 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 (dcl.init).
[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. ]

Initializing only one member in a C struct for an array of struct elements

It's not C Standard, but with this gcc extension you can do this :

struct some many[10] = { [0 ... 9].b = 5 };

It works with clang >= 5 too.

Default initialization for a struct in C

Unfortunately, you can't, but if you do this a lot, you could create a constant that you use for initialization:

struct data_msg {
uint8_t id;
uint8_t data1;
uint32_t data2;
};

const struct data_msg dm_init = {.id = 25};

int main(void) {
struct data_msg var = dm_init; // var.id is now 25, data1 = 0, data2 = 0
// ...
}

Default values in a C Struct

While macros and/or functions (as already suggested) will work (and might have other positive effects (i.e. debug hooks)), they are more complex than needed. The simplest and possibly most elegant solution is to just define a constant that you use for variable initialisation:

const struct foo FOO_DONT_CARE = { // or maybe FOO_DEFAULT or something
dont_care, dont_care, dont_care, dont_care
};
...
struct foo bar = FOO_DONT_CARE;
bar.id = 42;
bar.current_route = new_route;
update(&bar);

This code has virtually no mental overhead of understanding the indirection, and it is very clear which fields in bar you set explicitly while (safely) ignoring those you do not set.

default value for struct member in C

Structure is a data type. You don't give values to a data type. You give values to instances/objects of data types.

So no this is not possible in C.

Instead you can write a function which does the initialization for structure instance.

Alternatively, You could do:

struct MyStruct_s 
{
int id;
} MyStruct_default = {3};

typedef struct MyStruct_s MyStruct;

And then always initialize your new instances as:

MyStruct mInstance = MyStruct_default;


Related Topics



Leave a reply



Submit