Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What does initializing a string to {0, } do?

I've seen code like this:

char str[1024] = {0, };

and suspect that it is similar to doing this:

char str[1024];
str[0] = '\0';

But I couldn't find anything on it so I'm not sure.

What is this (called) and what does it do?


Disclaimer: I'm aware this might have been asked and answered before, but searching for {0, } is astonishingly hard. If you can point out a duplicate, I'll happily delete this question.

like image 566
domsson Avatar asked Mar 03 '23 08:03

domsson


2 Answers

No, they are not the same.

This statement

char str[1024] = {0, };

initializes the first element to the given value 0, and all other elements are to be initialized as if they have static storage, in this case, with a value 0. Syntactically this is analogous to using

char str[1024] = {0};

Quoting C11, chapter 6.7.9, p21

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, from p10 (emphasis mine)

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;

On the other hand

char str[1024];
str[0] = '\0';

only initializes the first element, and the remaining elements remains unitialized, containing indeterminate values.

like image 68
Sourav Ghosh Avatar answered Mar 05 '23 17:03

Sourav Ghosh


The {0, } initializer is the same as the more common {0} initializer. The trailing comma is allowed by the syntax but it makes no difference.

6.7.9--Initialization:

      initializer:
               assignment-expression
               { initializer-list }
               { initializer-list , }
      initializer-list:
               designationopt initializer
               initializer-list , designationopt initializer
      designation:
             designator-list =
      designator-list:
             designator
             designator-list designator
      designator:
             [ constant-expression ]
             . identifier

The semantics are such that the 0, which is syntactically required because at least one initializer-list item is syntactically required (it's a kind of a arbitrary requirement: compilers frequently support an empty {} as well) initializes the first subobject recursively (6.7.9p17):

Each brace-enclosed initializer list has an associated current object. When no designations are present, subobjects of the current object are initialized in order according to the type of the current object: array elements in increasing subscript order, structure members in declaration order, and the first named member of a union.148) In contrast, a designation causes the following initializer to begin initialization of the subobject described by the designator. Initialization then continues forward in order, beginning with the next subobject after that described by the designator.

and the rest is initialized as it would be if the whole object had static storage duration (6.7.9p19,6.7.9p21). This practically means to 0 (as with memset(,0,) although with the caveat that paddings need not be initialized and that 0-initialized pointers need not necessarily be "all-bits zero".

As far as I know, compilers on usual platforms (where pointers are all-bits-zero) just mostly do what they would do with memset(,0,).

This "universal" zero initialization works because the first 0 will recursively hit a scalar type (number on pointer) which can be invariably initialized with the 0 initializer. The default "as-with-static-storage-duration" then initialization applies to the rest.

A perhaps slightly more interesting of the trailing initializer comma doing nothing would be:

int main()
{
    char one[]={0,}; //<the comma doesn't introduce another member
    _Static_assert(sizeof(one)==1,""); //holds
}
like image 33
PSkocik Avatar answered Mar 05 '23 18:03

PSkocik