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.
Related
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.
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.
The following code is the basic implementation of the if - else conditional statements -
#include <stdio.h>
#include <stdlib.h>
int x;
int main()
{
if(x)
printf("hi");
else
printf("how r u \n");
return 0;
}
6.9.2 External object definitions
Semantics
1 If the declaration of an identifier for an object has file scope and an initializer, the
declaration is an external definition for the identifier.
2 A declaration of an identifier for an object that has file scope without an initializer, and
without a storage-class specifier or with the storage-class specifier static, constitutes a
tentative definition. If a translation unit contains one or more tentative definitions for an
identifier, and the translation unit contains no external definition for that identifier, then
the behavior is exactly as if the translation unit contains a file scope declaration of that
identifier, with the composite type as of the end of the translation unit, with an initializer
equal to 0.
So, Global variables are never left uninitialized, they are always initialized to 0. Hence the output how r u.
According to the C standard, your code does not trigger undefined behaviour:
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;
This is taken from the C11 standard, but C89, and C99 both defined this behaviour, too:
If an object that has static storage duration is not initialized explicitly, it is initialized implicitly as if every member that has arithmetic type were assigned 0 and every member that has pointer type were assigned a null pointer constant.
Because you're declaring x as a global variable, it has static storage duration, and therefore x is guaranteed to be initialized to 0 (it being an int, it obviously has an arithmetic type).
Your main function, therefore reads like this:
int main(void)//use int main(void), not int main()
{
if(0)//x is 0, 0 is false
printf("hi");
else
printf("how r u \n");//because if (x) is false, this is executed
return 0;
}
That's why the output of your program will be "How r u".
//global
int x;
You have declared 'x' as global variable ... Therefore it's default value is 0 .
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 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.