Are thread_local objects initialized to 0 in C? - c

Are non-local thread storage duration objects initialized to 0 in C?
static thread_local int x; // is x initialized to 0?
The C17 standard says the below (in 6.2.4.4).
An object whose identifier is declared with the storage-class specifier _Thread_local has thread
storage duration. Its lifetime is the entire execution of the thread for which it is created, and its
stored value is initialized when the thread is started.
It does not explicitly say it is initialized to 0. But the C++
standard makes it explicit and says: (in 3.6.2.2)
Variables with static storage duration ([basic.stc.static]) or thread
storage duration ([basic.stc.thread]) shall be zero-initialized
([dcl.init]) before any other initialization takes place
So, does C initialize non-local thread_local objects to 0 or not?

Thread local objects without explicit initialization are initialized to “zero.”
C 2018 7.26.1 3 says thread_local expands to _Thread_local if <threads.h> is included. That is not shown in the question, but presumably it is.
C 2018 6.2.4 4 says “An object whose identifier is declared with the storage-class specifier _Thread_local has thread storage duration…
C 2018 6.7.9 10 says:
… 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;
The paragraph ends there; the trailing “;” instead of a period is a typographical error.

Related

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.

structure on the stack - fields initialized? [duplicate]

This question already has an answer here:
C struct automatic initialization values, array initializations
(1 answer)
Closed 4 years ago.
Consider the following code:
void func()
{
int p;
...
if (p > MAX) {
struct my_struct s;
...
/* here we access the contents 's' as '&s' */
}
}
In this snippet s is on the stack. Is it guaranteed that the compiler initializes all structure fields to zero?
If a variable (struct or otherwise) is declared local to a function or a containing scope (i.e. has automatic storage duration), it is not initialized in any way. You need to explicitly set the fields in the struct.
If you initialize at least one field of a struct but not all, then the remaining fields will be initialized the same as file scope variables (i.e. variables with static storage duration), which means NULL for pointer types and 0 for numeric types.
From section 6.7.9 of the C standard:
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;
...
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.
No, it's quite the opposite.
Since s is an automatic storage local scoped (i.e., block scoped) variable, unless initialized explicitly, the contents are indeterminate.
Quoting C11, chapter §6.7.9
If an object that has automatic storage duration is not initialized explicitly, its value is
indeterminate. [...].
However, if you want to zero-initialize the variable for an(y) aggregate type, you can simply use an initialization statement like
aggregate-type variable = {0};
which uses the following property from paragraph 21 of the same chapter, (emphasis mine)
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.
No, they won't be initialized at all. The structure values will end up with whatever garbage is on the stack where the structure is placed.

Using an uninitialized global variable (for read and write) is OK?

If I use uninitialized global variable in C program, What happens? Is it undefined behavior?
#include <stdio.h>
int i;
int main()
{
while(i < 5)
{
i++;
}
printf("%d\n", i);
return 0;
}
Is it undefined behavior?
No.
What happens?
i has static storage duration (file scope). It will initialize to zero by default.
TL;DR No, you're fine.
But don't take my word for it, let's also see a bit more on the why part, following the authoritative sources.
First of all, let's see the scopes of the identifiers (variable).
Note:all emphasis mine
As per C11, chapter §6.2.1
If the declarator or type specifier that declares the identifier
appears outside of any block or list of parameters, the identifier has file scope, which
terminates at the end of the translation unit.
Then, from chapter §6.2.2
[...] If
the declaration of an identifier for an object has file scope and no storage-class specifier,
its linkage is external.
and, finally, for the storage class, chapter §6.2.4,
An object whose identifier is declared without the storage-class specifier
_Thread_local, and either with external or internal linkage or with the storage-class
specifier static, has static storage duration.
So, the global variable you mentioned has static storage duration.
Now, you say, it is not initialized explicitly, lets see what the spec has to say about this.
Quoting chapter §6.7.9/P10,
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, the variable has a defined value even without explicit initialization, so using that variable to read is perfectly OK. No undefined behavior here.

The initialization of static variables in 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

What does printf print for an unitialized variable?

What should the code print? 0 or any garbage value or will it depend on the compiler?
#include <stdio.h>
int a;
int main()
{
printf("%d\n",a);
return 0;
}
the answer is 0. Global variables are initialized to zero.
I would say your code might output anything or simply anything can happen because your code invokes Undefined Behaviour as per C99.
You don't have a prototype for printf in scope.
J.2 Undefined behavior
— For call to a function without a function prototype in scope where the function is defined with a function prototype, either the prototype ends with an ellipsis or the types of the arguments after promotion are not compatible with the types of the parameters (6.5.2.2).
If the question is about initialization of global variables then a would be initialized to 0 because it has static storage duration.
I found on C99 standard, Section 6.7.8.10, Initialization:
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.
Section 6.2.4.3 defines:
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.
In other words, globals are initialized as 0. Automatic variables (i.e. non-static locals) are not automatically initialized.
without automatic variable [generally what we use in function in most cases] all other variable's value is assigned to 0
Global variables are initialized as 0. Automatic variables (i.e. non-static locals) are not automatically initialized.

Resources