82

For example, if somestruct has three integer members, I had always thought that it was OK to do this in C (or C++) function:

somestruct s = {123,};

The first member would be initialized to 123 and the last two would be initialized to 0. I often do the same thing with automatic arrays, writing int arr[100] = {0,}; so that all integers in an array are initialized to zero.


Recently I read in the GNU C Reference Manual that:

If you do not initialize a structure variable, the effect depends on whether it is has static storage (see Storage Class Specifiers) or not. If it is, members with integral types are initialized with 0 and pointer members are initialized to NULL; otherwise, the value of the structure's members is indeterminate.


Can someone please tell me what the C and C++ standards say regarding partial automatic structure and automatic array initialization? I do the above code in Visual Studio without a problem but I want to be compatible with gcc/g++, and maybe other compilers as well. Thanks

loop
  • 3,460
  • 5
  • 34
  • 57

3 Answers3

117

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

Alok Save
  • 202,538
  • 53
  • 430
  • 533
  • Thanks for this thorough answer. Concerning value initialization, do you happen to know if in C++ an expression of the form DWORD() is guaranteed to be 0? Björn commented on my question and linked a question concerning value initialization, but it is unclear to me whether or not Visual Studio supports that because it's C++98, not C++03. – loop Jun 01 '12 at 00:57
  • @test: AFAIK, in C++98 there were only two types of initialization, *Zero Initialization* & *Default Initialization*, C++03 added *Value Initialization*, `DWORD()` in C++98 would be evaluated as *Zero Initialization*. – Alok Save Jun 01 '12 at 03:04
  • 6
    `then the uninitialized elements must be initialized to 0.` umm... no. They are not initialized to zero, but to `initialized implicitly the same as objects that have static storage duration`, which may be zero and currently probably is zero for all standard C types, but the standard does not explicitly require zero. Sorry for the nitpicking but it's bit strange if you say something and then quote a standard that says something else (even if you are probably both right with what you say). – Mecki Aug 25 '17 at 15:40
  • @Mecki: Good point. It was a overly simplistic generalization in the answer. – Alok Save Aug 25 '17 at 17:48
  • @Mecki Hey, so if I don't initialize any value to an array inside a curly bracket then is it by default initialized with 0, right...like int arr[2] = {}; and other one, int arr[2] = {0}; – codosopher Apr 29 '23 at 15:17
  • @codosopher My comment was only about the fact that the standard does not guarantee anything is ever initialized to 0, it only guarantees that things are initialized the same way as static variables (which is 0 on all platforms I'm aware of but doesn't have to be). Stack variables are not required to be initialized by the standard; a compiler or system is allowed to do so but you must not rely on this being the case and usually it isn't (except for debug builds on some platforms). – Mecki May 02 '23 at 09:10
  • 2
    @codosopher If you do this `int ar[100];`, `ar` is usually not initialized at all and has random values. If you do this `int ar[100]; ar[5] = 0;` then only `ar[5]` is initialized to 0, the rest is still random. If you use `int ar[100] = { 0 };`, then `ar[0]` is initialized to 0, the rest get the value of a static variable which may be 0 but doesn't have to. The only standard conform way to initialize an array to all zero for sure is `int ar[100]; memset(ar, 0, sizeof(ar));` – Mecki May 02 '23 at 09:14
  • @Mecki but as we know, static variables by default 0 or NULL if they are not initialized in C++. – codosopher May 02 '23 at 14:21
  • @codosopher According to standard, an arithmetic type is initialized to either positive or unsigned zero; note that C allows positive and negative zero to exist as the standard does not require integers to use two's complement representation (one's complement and even something else is totally legit for signed values). A pointer is initialized to "null pointer" (`NULL` is not value, it is a macro that expands to a "null pointer constant" according to standard). But if the next std defines a new type tomorrow, that type may be initialized to something else and that would still be valid. – Mecki May 02 '23 at 16:04
18

In C, objects are never partially initialised - if any part of them is initialised, the entire object (and all sub-objects recursively) are initialised. If no explicit initialiser is provided then elements are initialised to "zero of the appropriate type".

The quote in your question is referring to when the initialiser for the entire object is completely left out, not when a sub-object lacks an initialiser. For example, assuming that arr has automatic storage duration, then this:

int arr[100] = { 123 };

initialises arr[0] to 123 and every other element of arr to 0. Whereas this:

int arr[100];

leaves every element of arr uninitialised. It is this latter case that the quote is in reference to.

caf
  • 233,326
  • 40
  • 323
  • 462
  • In this case ,int arr[100] = { 123 }; , is every other remaining element of array arr initialized to ASCII 0 or numeric 0 ? – Radha Gogia Jul 14 '18 at 12:30
  • @RadhaGogia: numeric 0. – caf Jul 14 '18 at 14:09
  • Is there any way to check out this so as to confirm that it is not ASCII 0 , because while I do %c , it prints nothing so I want to know how to confirm if compiler fills remaining entries with null (ASCII 0 ) or numeric 0 ? – Radha Gogia Jul 16 '18 at 01:08
  • @RadhaGogia: Numeric/integer zero *is* the ASCII null character when printed using `%c`. – caf Jul 20 '18 at 03:47
  • `'\0'` is null (i.e., `(char)0`); `'0'` is ASCII 0 (i.e. `(char)48`). – geometrian Dec 01 '20 at 23:50
  • "Some compilers" may operate this way -- gcc does not. C has no default initialization for non-static storage. struct astruct A = {0}; is a compiler sugar syntax that works on some compilers to zero out all members. – Chris Reid Dec 03 '22 at 22:11
  • @ChrisReid: `struct astruct A = { 0 };` initialising all members and submembers to zero of the appropriate type is not "some compilers", it is mandated by the C standard. GCC absolutely does so. Eg this example: https://godbolt.org/z/MdohEabn5 – caf Dec 04 '22 at 23:10
5

newest gcc versions also allow to "partially" initialize and zeromem at the same time:

typedef struct{
  int a,b,c;
}T;

T s = {0, .b=5};

the struct members now will have these values: a=0, b=5, c=0

i don't have any info on whether other compilers allow this or not :p

rocket441
  • 277
  • 3
  • 7
  • 8
    This is a C99 feature, not particularly new. It's called "designated initializer" and is widely supported. It's not a C++ feature, though. C++ uses constructors. – MSalters Feb 26 '13 at 19:55