Assignment of unreferenced variables? - c

I saw the following code in the wild and I don't know what to make of it:
more or less:
int main(void)
{
int a = 0, v;
printf("%d\n", v);
}
This code with gcc will print out 0. At first I though, oh well that's because initialized local variables are assigned 0, but in this case I never declared the type of v...so what gives?

int a = 0, v;
is equivalent to:
int a = 0;
int v;
So you did declare the type of v, just not explicitly. It's an int.
Anyway, like all uninitialized local variables, v's value isn't guaranteed to be anything. Accessing it is still undefined behavior; you just happened to get 0.

What do you think the comma does in a declaration statement?
In C - C99 and C++, an initializer is an optional part of a declarator. The init-declarator-list is a comma-separated sequence of declarators, each of which can have additional type information, or an initializer, or both.
As such, your expression int a = 0, v; does declare v as a an int.

Type of v is int. Please read the syntax of variable declaration.
You are just lucky that it is printing 0. Value of v is garbage.

From ISO/IEC 9899:TC2 section 6.7.8 Semantics
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.

From Wiki,
Multiple variables can be declared with one statement, like this:
int anumber, anothernumber, yetanothernumber;

Related

Value of uninitialized elements in array of C language

I have an array of 3 elements. But I only want to initialize 2 of them.
I let the third element blank.
unsigned char array[3] = {1,2,};
int main(){
printf("%d",array[2]);
return 0;
}
The print result is 0. I tested it on IAR, and some online compiler.
Is there any C rule for the value of third element?
Is there any compiler filling the third element by 0xFF ? (Especially cross compiler)
Yes, the C standard does define what happens in this case. So no, there should be no C standard compliant compiler that intialises with 0xFF in this case.
Section 6.7.9 of the standard says:
Initialisation
...
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;
...
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.
From this post, it appears that that syntax will initialize all elements after the comma to zero. Moreover; all uninitialized data in the data segment of the program (in other words all uninitialized global variables) are automatically set to zero, so if you are looking for undefined behavior in this program, there isn't any; it will always be 0.
This can be achieved with gcc extension as below
unsigned char array[10] = {1,2,[2 ... 9] = 0xFF};

What is the default value of char in c

When I declare an int variable, and do not not assign a value to it, and then when I print it, a random number gets printed.
but when I allocate a char variable, and print it with %c format specifier, nothing is printed. So does a char variable in C have a default value like null? Do local variables in C start with a random value? Then why doesn't a char behave in this way?
There is no default value which is assigned to it. Some values are not printable and you can assume that random value is one of them, so that is the reason why you are not able to see the result.
The C99 standard says that:
If an object that has automatic storage duration is not initialized
explicitly, its value is indeterminate.
On a side note:
As per C99
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.
Automatic variables that are not initialized have indeterminate value, we can see this by going to the draft C99 standard section 6.7.8 Initialization:
If an object that has automatic storage duration is not initialized explicitly, its value is
indeterminate.
using an indeterminate value is undefined behavior. The definition for indeterminate values is as follows:
either an unspecified value or a trap representation
It just may be the case that the values you are ending up with for char are not printable.
There is not default value assigned. Never trust in a default value you didn't assign.

Which member of a global union variable that is not initialized explicitly will be initialized to 0 implicitly?

e.g.
union
{
int n;
void *p;
} u;
Is the initial value of u.n or that of u.p equal to 0?
It should be noted that a NULL pointer is not necessarily stored in all-zero bits. Therefore, even if u.n and u.p have the same size,
u.n == 0
doesn't guarantee
u.p == 0
and vice versa.
(Sorry for my poor English)
if Object with 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 u.n will be initilaized to zero and u.p is undetermined.
EDIT: Response to comment
above info copied from ISO/IEC 9899:201x 6.7.9.10
Since u is static then the first member will be initialized to zero, from the C99 draft standard section 6.7.8 Initialization paragraph 10:
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.
since n is a arithmetic type it will be initialized to zero. The value of p is unspecified but in practice type punning is usually supported by the compiler for example the gcc manual points here for Type-punning and we can see under -fstrict-aliasing section is says:
The practice of reading from a different union member than the one most recently written to (called “type-punning”) is common. Even with -fstrict-aliasing, type-punning is allowed, provided the memory is accessed through the union type.
It is also worth noting that you may be able to initialize any member of a union like so:
union { int n; void *p; } u = { .p = NULL } ;
^^^^^^^^^^^^^
I am not sure if all compilers support this though.
I think by 'global variable' you mean that it's at file scope. If so, and if it's declared 'static', it will be initialized to all zero bits, eg because it gets allocated in .BSS.
What those zero bits in the union's storage mean in terms of the value of whichever of its members you access depends on their types. In your case, all zero bits in an int means it has the value zero, and all zero bits in a pointer makes it NULL, ie #Dukeling's bang on here.
I am not sure that all zero bits in a float would yield a float with value zero.
It depends upon how you instantiate the variable itself. Usually static defined variables are initialized to zero. If you malloc the union to a pointer, you may get uninitialized memory. However, if you use calloc to allocate memory for the union, calloc will initialized the allocated memory to zero per the man page.
It may also depend on any libraries that you may be using. Google's perftools library may or may not zero out the memory when you make the call to calloc that it overwrites.

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