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 .
Related
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.
What is the concept when we define a global array with no dimension
This shows output as 16.
#include <stdio.h>
#include <stdlib.h>
int arr[];
int main(int argc, char *argv[])
{
arr[1] = 16;
printf("%d\n",arr[1]);
system("PAUSE");
return 0;
}
And even sizeof(arr) doesn't work. Why?
int arr[]; is a tentative definition there.
Clause 6.9.2, paragraph 2 says:
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.
and example 2 in paragraph 5 of that clause clarifies:
If at the end of the translation unit containing
int i[];
the array i still has incomplete type, the implicit initializer causes it to have one element, which is set to zero on program startup.
So at the end of the translation unit, your array arr has type int[1]. Before the end, its type is incomplete, hence sizeof doesn't work, since in main, the array type is still incomplete.
Accessing arr[1] invokes undefined behaviour, since arr has only one element.
GCC assumes that arr should only have one element. The fact that you can access other elements than arr[0] without segfaulting is just a coincidence. For instance, on my machine I can access arr[1], arr[10] and arr[100] just fine, but arr[1000] causes a segfault. In general, accessing locations outside array bounds causes undefined behavior.
What is the concept when we define a global array with no dimension
This shows output as 16.
#include <stdio.h>
#include <stdlib.h>
int arr[];
int main(int argc, char *argv[])
{
arr[1] = 16;
printf("%d\n",arr[1]);
system("PAUSE");
return 0;
}
And even sizeof(arr) doesn't work. Why?
int arr[]; is a tentative definition there.
Clause 6.9.2, paragraph 2 says:
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.
and example 2 in paragraph 5 of that clause clarifies:
If at the end of the translation unit containing
int i[];
the array i still has incomplete type, the implicit initializer causes it to have one element, which is set to zero on program startup.
So at the end of the translation unit, your array arr has type int[1]. Before the end, its type is incomplete, hence sizeof doesn't work, since in main, the array type is still incomplete.
Accessing arr[1] invokes undefined behaviour, since arr has only one element.
GCC assumes that arr should only have one element. The fact that you can access other elements than arr[0] without segfaulting is just a coincidence. For instance, on my machine I can access arr[1], arr[10] and arr[100] just fine, but arr[1000] causes a segfault. In general, accessing locations outside array bounds causes undefined behavior.
A highly reputed contributor "R.." on this forum explicitly told me this 2 days back:
Initializers for objects of static storage duration must be constant expressions. The result of a function call is not a constant expression.
He was talking about global variables.But I am not sure what goes with constants declared inside the main() function, or any function for that matter.Though intuitively I feel it is so even for constants declared within functions,the following program sourced from the following link, with its supposedly correct answer, is confusing me.
http://www.indiabix.com/c-programming/const/discussion-546
#include<stdio.h>
int get();
int main()
{
const int x = get();
printf("%d", x);
return 0;
}
int get()
{
return 20;
}
So can anyone explain whether it's valid in C to assign a return value to a constant?
Yes, it's perfectly valid, since your variable is automatic, i.e. not static.
The restrictions apply to static variables, whose values must be known at compile-time.
Note that C differentiates between "constant expressions" and other expressions, and that the initializer value used for static variables must be such a constant expression. For non-static variables, there is no such requirement.
Yes, this assignment is valid C. But x is not a constant expression, it is a const-qualified variable, which is not the same thing (in C at least).
C11 (n1570), § 6.6 Constant expressions
An integer constant expression shall have integer type and shall only have operands
that are integer constants, enumeration constants, character constants, sizeof
expressions whose results are integer constants, _Alignof expressions, and floating
constants that are the immediate operands of casts.
Integer constants look like 42, 0L or 89.0. For example, in the following code snippet, 2 is an integer constant, but x is not.
const int x = 2;
What I think makes you confused is that you are mixing up the type qualifier const, with the storage class specifier static. These are entirely different features, you can't compare them with each other.
const means that a variable is read-only within the scope where it was declared, and it can only be given a value when it is initialized. That is, on the same line where the const variable was defined. It means nothing else.
Static storage duration means that a variable will exist throughout the whole execution of a program. All variables that are declared as static and all variables that declared at file scope ("globals") have static storage duration. As mentioned, variables with static storage duration can only be initialized with a constant expression, which is not to be confused with read-only variables declared as const.
So can anyone explain whether it's valid in C to assign a return value to a constant?
It depends.
Any variable declared at file scope has static storage duration.
A variable with static storage duration must be initialized with a constant expression.
A return value from a function is not a constant expression.
Thus a variable with static storage duration cannot be initialized with a return value from a function.
As you can see, that had nothing to do with the const keyword but everything to do with where the variable was declared. Had the variable, const or not, been declared inside a local scope, it would be perfectly fine to initialize it with any value, as illustrated by your code example.
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.