C and C++: Partial Initialization of Automatic Structure

C and C++ : Partial initialization of automatic structure

The linked gcc documentation does not talk of Partial Initialization it just talks of (Complete)Initialization or No Initialization.

What is partial Initialization?

The standards do not define Partial initialization of objects, either there is Complete initialization or No-initialization. Partial Initialization is a non-standard terminology which commonly refers a situation where you provide some initializers but not all i.e: Fewer initializers than the size of the array or the number of structure elements being initialized.

Example:

int array[10] = {1,2};                    //Case 1:Partial Initialization

What is (Complete)Initialization or No Initialization?

Initialization means providing some initial value to the variable being created at the same time when it is being created. ie: in the same code statement.

Example:

int array[10] = {0,1,2,3,4,5,6,7,8,9};    //Case 2:Complete Initialization
int array[10]; //Case 3:No Initialization

The quoted paragraph describes the behavior for Case 3.

The rules regarding Partial Initialization(Case 1) are well defined by the standard and these rules do not depend on the storage type of the variable being initialized.

AFAIK, All mainstream compilers have 100% compliance to these rules.


Can someone please tell me what the C and C++ standards say regarding partial automatic structure and automatic array initialization?

The C and C++ standards guarantee that even if an integer array is located on automatic storage and if there are fewer initializers in a brace-enclosed list then the uninitialized elements must be initialized to 0.

C99 Standard 6.7.8.21

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.


In C++ the rules are stated with a little difference.

C++03 Standard 8.5.1 Aggregates

Para 7:

If there are fewer initializers in the list than there are members in the aggregate, then each member not explicitly initialized shall be value-initialized (8.5).
[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. ]

While Value Initialization is defined in,

C++03 8.5 Initializers

Para 5:

To value-initialize an object of type T means:

— if T is a class type (clause 9) with a user-declared constructor (12.1), then the default constructor for T is called (and the initialization is ill-formed if T has no accessible
default constructor);

— if T is a non-union class type without a user-declared constructor, then every non-static
data member and base-class component of T is value-initialized;

— if T is an array type, then each element is value-initialized;

— otherwise, the object is zero-initialized

Partially initializing a C struct

When you do this:

struct s myStruct;
myStruct.si = 9;

You are not initializing myStruct. You declare it without an initializer, then run a statement to set one field.

Because the variable is uninitialized, its contents are undefined, and reading it is undefined behavior. This means that seemingly unrelated changes can modify this behavior. In your example adding an extra variable happened to cause myStruct.sj to be 0, but there's no guarantee that this will be the case.

To initialize a variable, you have to give it a value at the time it is defined:

struct s myStuct = { 9 };

One you do this, then you'll see the contents of myStruct.sj set to 0. This is guaranteed as per section 6.7.8 of the C standard (with highlighting specific to this case):

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.

...

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

What happens when there is partial initialization of an array of struct in C?

The entire array will be initialized with structs with the value 0 for both a and b. This is similar to the following case with a primitive value:

int foo[10] = {0};

Where every integer in the array will be initialized with the value 0.

The C99 standard specifies the following:

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.

Partial initialization for an array of structures in C

If an array or struct is only partially initialized, any containing objects without an explicit initializer are set to 0 or NULL.

Partial initialization is covered in section 6.7.9p21 of the C11 standard:

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 initialization of objects with static storage duration are covered in section 6.7.9p10:

If an object that has automatic storage duration is not
initialized explicitly, its value is indeterminate. If an
object that has static or thread 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,and any padding is initialized to zero bits;
  • if it is a union, the first named member is initialized (recursively) according to these rules, and any padding is initialized
    to zero bits

So in your particular case, all array elements will have the num member set to 0 and the str member set to NULL.

How to initialize a struct in accordance with C programming language standards

In (ANSI) C99, you can use a designated initializer to initialize a structure:

MY_TYPE a = { .flag = true, .value = 123, .stuff = 0.456 };

Other members are initialized as zero: "Omitted field members are implicitly initialized the same as objects that have static storage duration." (https://gcc.gnu.org/onlinedocs/gcc/Designated-Inits.html)

Initializing a Struct of a Struct

Initialisers can be nested for nested structs, e.g.

typedef struct {
int j;
} Foo;

typedef struct {
int i;
Foo f;
} Bar;

Bar b = { 0, { 0 } };

Partial assignment of struct in C99+

Point 6 in section 6.5.2.5 Compound literals of the C99 standard states:

The value of the compound literal is that of an unnamed object initialized by the initializer list.

The unnamed foo_t is partially initialized, by the same rules you mention.

The last statement is an assignment, but the compound literal is an unnamed object initialized by the initializer list. Meaning the unnamed.a has value zero and f.a is zero after the assignment.

Initializing a struct to 0

The first is easiest(involves less typing), and it is guaranteed to work, all members will be set to 0[Ref 1].

The second is more readable.

The choice depends on user preference or the one which your coding standard mandates.

[Ref 1] Reference C99 Standard 6.7.8.21:

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.

Good Read:

C and C++ : Partial initialization of automatic structure

Are uninitialized members of partially-defined static objects guaranteed initialized to 0?

All remaining elements are initialized to zero (for arithmetic types) or a null pointer (for pointers). C 2018 6.7.9 21 says:

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.

6.7.9 10 says objects with static storage duration are, effectively, initialized with zero:

… If an object that has static or thread 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, and any padding is initialized to zero bits;

— if it is a union, the first named member is initialized (recursively) according to these rules, and any padding is initialized to zero bits;



Related Topics



Leave a reply



Submit