The initialization of static variables in C - c

I have a question about the initialization of static variables in C. I know if we declare a global static variable that by default the value is 0. For example:
static int a; //although we do not initialize it, the value of a is 0
but what about the following data structure:
typedef struct
{
int a;
int b;
int c;
} Hello;
static Hello hello[3];
are all of the members in each struct of hello[0], hello[1], hello[2] initialized as 0?

Yes, all members are initialized for objects with static storage. See 6.7.8/10 in the C99 Standard (PDF document)
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.
To initialize everything in an object, whether it's static or not, to 0, I like to use the universal zero initializer
sometype identifier0 = {0};
someothertype identifier1[SOMESIZE] = {0};
anytype identifier2[SIZE1][SIZE2][SIZE3] = {0};
There is no partial initialization in C. An object either is fully initialized (to 0 of the right kind in the absence of a different value) or not initialized at all.
If you want partial initialization, you can't initialize to begin with.
int a[2]; // uninitialized
int b[2] = {42}; // b[0] == 42; b[1] == 0;
a[0] = -1; // reading a[1] invokes UB

Yes, they are, as long they have static or thread storage duration.
C11 (n1570), § 6.7.9 Initialization #10
If an object that has static or thread storage duration is not initialized
explicitly, then:
[...]
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;
[...]

Yes, file-scope static variables are initialized to zero, including all members of structures, arrays, etc.
See this question for reference (I'll vote to close this as a duplicate, too).
Edit: this question is getting much better answers, so I'm voting to close that question as a duplicate of this, instead.
For reference, here is the C FAQ link from that question's accepted answer, although of course the C99 and C11 standards linked here are canonical.

I would add that static variables (or arrays) are classified into two types.
Initialized are the ones that are given value from code at compile time. These are usually stored in DS though this is compiler specific.
The other type is uninitialized statics which are initialized at run time and are stored into BSS segment though again this is compiler specific.
BSS

For the ones who don't want to read the standard, it's also mentioned in https://en.cppreference.com/w/c/language/initialization :
Implicit initialization
If an initializer is not provided:
objects with automatic storage duration are initialized to indeterminate values (which may be trap representations)
objects with static and thread-local storage duration are zero-initialized

Related

Partial initialization for an array of structures in C

While revising my C knowledge, I stumbled into the following example:
#include <stdio.h>
/* Just a simple structure */
typedef struct lab {
int num;
char *str;
} bal;
int main (void) {
/* Declare and _partially_ initialize an array of the structure above... */
bal struct_array[10] = { {0, NULL} };
/* Question: what does _exacly_ happen to the other 9 members of the array? */
return 0;
};
The comment in the code should be enough to provide my question. In other words, what does it happen if we partially initialize an array of structs? Sure, I know that (at least) for C++11 there is the default initialization. But does it hold for pure C, too? If yes, is it true for all the standards (from C89 on), or just for some in particular? Thank you.
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.

need to memset global strings or strings inside global structs

Do we need to memset global C style strings or is it initiated to '\0' on its own?
for example:
char c_string[10];
OR
struct node
{
int x;
char y[10];
};
Global variables having arithmetic types (including char) are initialized to zero, so you don't use memset() for the first initialization.
Quote from N1570 6.7.9 Initialization 10:
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;
File scope variables ("global") have static storage duration. All variables with static storage duration are automatically initialized to zero (or NULL).
However, relying on this initialization is bad practice - it is better to make a habit of writing
char c_string[10] = "";
even if that makes no practical difference. This is self-documenting code meaning that you have actually considered the zero-initialization, rather than char c_string[10]; which could as well mean that you got it right by luck.

Automatic storage duration struct initialization

Some of this may be a duplicate, but I am sorry for that.
Let's say I have this struct:
struct foo
{
int a;
int b;
int c;
};
1. If struct foo type object is declared in the way that it has automatic storage duration and without initializers, is it guaranteed that all it's members will be force initialized to zero?
{
// other stuff
struct foo bar;
// other stuff
}
2. If struct foo type object is declared in the way that it has automatic storage duration and with some initializers, is it guaranteed that members, which are not explicitly initialized, will be force initialized to zero?
{
// other stuff
struct foo bar = {.a = 1};
// other stuff
}
3. If struct foo type object is declared in the way that it has automatic storage duration and by using compound literal expression, is it guaranteed that members, which are not explicitly initialized, will be force initialized to zero?
{
// other stuff
func((struct foo){.a = 1});
// other stuff
}
Any C standard references are much appreciated! Thank you!
Summary, TL;DR:
Storage duration explained:
A variable declared inside a function has automatic storage duration (including parameters to functions).
A variable declared as static, or a variable declared outside functions at file scope ("global") has static storage duration.
Struct (and array) initialization explained:
If you initialize no member and the struct has automatic storage duration, nothing is initialized.
If you initialize no member and the struct has static storage duration, all members are zero-initialized.
If you initialize any member(s), those you didn't touch get initialized to zero.
The relevant part of the C standard (C17 6.7.9 §10):
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;
Where "artihmetic type" is standard gibberish for plain variables like int, and "aggregate" is standard gibberish for arrays and structs.
Further down in the same chapter (C17 6.7.9 §19):
...all subobjects that are not initialized explicitly shall be initialized implicitly the same as objects that have static storage duration.
Answers to your questions:
If struct foo type object is declared in the way that it has automatic storage duration and without initializers, is it guaranteed that all it's members will be force initialized to zero?
No, it is not guaranteed; their values are indeterminate as stated in the first sentence of the quote above.
If struct foo type object is declared in the way that it has automatic storage duration and with some initializers, is it guaranteed that members, which are not explicitly initialized, will be force initialized to zero?
Yes, as per C17 6.7.9 §19 cited above.
If struct foo type object is declared in the way that it has automatic storage duration and by using compound literal expression, is it guaranteed that members, which are not explicitly initialized, will be force initialized to zero?
Yes, since compound literals are arrays or structs, they follow the same initialization rules.
First of all, uninitialized variables with automatic storage will never be initialized. From The C11 standard (ISO/IEC 9899:2011 §6.7.9/10):
If an object that has automatic storage duration is not initialized explicitly, its value is indeterminate.
Then from this structure initialization reference:
All members that are not initialized explicitly are initialized implicitly the same way as objects that have static storage duration.
And if we follow the "initialized implicitly" link we have:
objects with static and thread-local storage duration are initialized as follows
...
objects of integral types are initialized to unsigned zero
...
So to answer your questions:
No, no initialization is done as there is no explicit initialization in your code (see the quote from the standard)
Yes, since this is a structure initialization
Yes, for same reason as 2.
The links provided have references to the standard.

Elements of a static structure

I would like to ask you: Are the elements of static structure initialized to zero? For example:
static struct _radioSettings
{
unsigned char radio_in;
unsigned char radio_out;
}radioSettings;
So this structure is placed in module radio-settings.c
If radioSettings.radio_in and radioSettings.radio_out are not initialized to zero at compilation how can I initialize them inside the module radio-settings.c?
All global variables are initialized to the default values.
Section 6.7.8 Initialization of C99 standard (n1256) says:
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.
So for your structure, each field is initialized to its default value, that is 0.
Static, in C, is related to the visibility of the structure, it does not mean anything else than it is not visible from outside module radio-settings.c.
Structures in C are not initialized to anything. The values for its fields are the memory values the structure landed in. So, you cannot count on anything like that.
If you want to initialize the structure, then it is simple:
memset( &radioSettings, 0, sizeof( _radioSettings ) );
You only have to place that in an init() function for the radioSettings, inside the module radio-settings.c
Hope this helps.

Unsigned int field of struct got automatically initialized?

Does C guarantees that an unsigned integer field inside a struct gets initialized to zero? In my system, it seems it does (or I am very "lucky"(actually unlucky)).
In code words, what will happen in the following scenario?
struct node {
unsigned int rec_size;
};
struct node node;
// what is the value of node.rec_size? Undefined or 0?
Relevant answer, but not the same, since in my example, there is only one field and no initialization.
The answer is, it depends on the storage-class:
If it is _Thread_local or static, it is guaranteed to be zeroed.
If it is auto or dynamic storage, no initialization takes place.
6.7.9 Initialization
10 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;
BTW: Zero-initialization in C++ is equivalent to those rules for static/thread-local objects.
No, the value is undetermined.
Value will be 0 only if the variable is static or global.

Resources