I have this question, which i thought about earlier, but figured it's not trivial to answer
int x = x + 1;
int main() {
return x;
}
My question is whether the behavior of the program is defined or undefined if it's valid at all. If it's defined, is the value of x known in main?
I'm pretty sure it's defined, and x should have the value 1. §3.6.2/1 says: "Objects with static storage duration (3.7.1) shall be zero-initialized (8.5) before any other initialization takes place."
After that, I think it's all pretty straightforward.
My question is whether the behavior of the program is defined or undefined if it's valid at all. If it's defined, is the value of x known in main?
This code is definitely not clean, but to me it should work predictably.
int x puts the variable into the data segment which is defined to be zero at the program start. Before main(), static initializers are called. For x that is the code x = x + 1. x = 0 + 1 = 1. Thus the main() would return 1.
The code would definitely work in unpredictable fashion if x is a local variable, allocated on stack. State of stack, unlike the data segment, is pretty much guaranteed to contain undefined garbage.
The 'x' variable in stored in the .bss, which is filled with 0s when you load the program. Consequently, the value of 'x' is 0 when the program gets loaded in memory.
Then before main is called, "x = x + 1" is executed.
I don't know if it's valid or not, but the behavior is not undefined.
Before the main call x must be initialized to 0 therefore it's value must be 1 one you enter main, and you will return 1. It's a defined behavior.
Related
int main()
{
{int x = 532;}
int xc;
int x = *(&xc+1);
cout << x << endl; // prints 532
}
I create an int variable with a value of 532 and then it immediately goes out of scope.
I then create another int variable right after so that it has an address of 1 word before x.
I then assign that value of whatever was one word past xc to x and print it, and it has the value of 532.
Is this guaranteed to happen? Why/why not?
No, the arrangement and padding (and even the existence) of variables on the stack is implementation-dependent, and what you have here is Undefined Behavior. The language specifies that you must not use a pointer to access the memory of any object other than the one it points to.
In this case, &xc + 1 points to memory that lies outside the allocation of xc. You cannot read or write to this location and expect any kind of predictable result. Note that it is actually a valid pointer -- you are allowed to point "one-past-the-end" of an allocation, provided you never dereference that address.
To explain what's actually happening in your case: your variables are being pushed onto the stack, and the stack memory extends in the direction of lower addresses. It appears your compiler didn't bother to unwind the stack after the original x went out of scope. Alternatively, multiple values of 532 might have been initialized in memory, or in a register, and the value you're reading might not be the one that was stored at x. All this said, even this program on your computer with your compiler does not guarantee this behavior.
The original variable x could be optimized away by the compiler completely because it is not used.
The value of xc is uninitialized. Its location (if any) on the stack is not guaranteed. Even though x had additional scope, the compiler is not required to push and pop stack locations if it doesn't want to.
The compiler is not required to understand that you're aliasing x via xc because, as already mentioned such behavior is not defined.
I just stumbled upon a behavior which surprised me:
When writing:
int x = x+1;
in a C/C++-program (or even more complex expression involving the newly created variable x) my gcc/g++ compiles without errors. In the above case X is 1 afterwards. Note that there is no variable x in scope by a previous declaration.
So I'd like to know whether this is correct behaviour (and even might be useful in some situation) or just a parser pecularity with my gcc version or gcc in general.
BTW: The following does not work:
int x++;
With the expression:
int x = x + 1;
the variable x comes into existence at the = sign, which is why you can use it on the right hand side. By "comes into existence", I mean the variable exists but has yet to be assigned a value by the initialiser part.
However, unless you're initialising a variable with static storage duration (e.g., outside of a function), it's undefined behaviour since the x that comes into existence has an arbitrary value.
C++03 has this to say:
The point of declaration for a name is immediately after its complete declarator (clause 8) and before its initializer (if any) ...
Example:
int x = 12;
{ int x = x; }
Here the second x is initialized with its own (indeterminate) value.
That second case there is pretty much what you have in your question.
It's not, it's undefined behavior.
You're using an uninitialized variable - x. You get 1 out of pure luck, anything could happen.
FYI, in MSVS I get a warning:
Warning 1 warning C4700: uninitialized local variable 'i' used
Also, at run-time, I get an exception, so it's definitely not safe.
int x = x + 1;
is basically
int x;
x = x + 1;
You have just been lucky to have 0 in x.
int x++;
however is not possible in C++ at a parser level! The previous could be parsed but was semantically wrong. The second one can't even be parsed.
In the first case you simply use the value already at the place in memory where the variable is. In your case this seems to be zero, but it can be anything. Using such a construct is a recipe for disaster and hard to find bugs in the future.
For the second case, it's simply a syntax error. You can not mix an expression with a variable declaration like that.
The variable is defined from the "=" on, so it is valid and when it is globally defined, it is initialized as zero, so in that case it is defined behavior, in others the variable was unintialized as as such still is unitialized (but increased with 1).
Remark that it still is not very sane or useful code.
3.3.1 Point of declaration 1 The point of declaration for a name is immediately after its complete declarator (clause 8) and before its
initializer (if any), except as noted below. [ Example: int x = 12; {
int x = x; } Here the second x is initialized with its own
(indeterminate) value. —end example ]
The above states so and should have indeterminate value, You are lucky with 1.
Your code has two possiblities:
If x is a local variable, you have undefined behavior, since you use the value of an object before its lifetime begins.
If x has static or thread-local lifetime, it is pre-initialized to zero, and your static initialization will reliably set it to 1. This is well-defined.
You may also wish to read my answer that covers related cases, including variables of other types, and variables which are written to before their initialization is completed
This is undefined behaviour and the compiler should at least to issue a warning. Try to compile using g++ -ansi .... The second example is just a syntax error.
I am getting different values for the a variable which is an int.
Although I know I am not initializing it, the value changes from 32767 32766 32765 and 32764 for variable a (with code version 1) and its always 0 with code version 2.
I know I don't have to leave variables uninitialized, just asked this question to see if anybody knew what is happening behind the scenes at runtime, I am using gcc .
whith code version 1
#include <iostream>
int main()
{
int a;
int *b = new int; // <----- this line
std::cout<<a<<std::endl;
std::cout<<*b<<std::endl;
return 0;
}
whith code version 2
#include <iostream>
int main()
{
int a;
std::cout<<a<<std::endl;
int *b = new int; // <----- same line moved here
std::cout<<*b<<std::endl;
return 0;
}
You read uninitialized memory. This is undefined behavior. That means the C++ language rules give literally no guarantee what happens when you run this code, at all. You may see the values you observed, nothing at all, crash your PC or set your house on fire. All equally legal outcomes of running this code.
In practice this will only print unpredictable garbage values in the range of int of course, dependent on what just happens to be left over in your memory and do nothing interesting.
Proof from the standard (N4140) for the non-believers:
When storage for an object
with automatic or dynamic storage duration is obtained, the object has an indeterminate value, and if
no initialization is performed for the object, that object retains an indeterminate value until that value is
replaced (5.17). [ Note: Objects with static or thread storage duration are zero-initialized, see 3.6.2. —
end note ] If an indeterminate value is produced by an evaluation, the behavior is undefined except in the
following cases:
[8.5 (12)], emphasize mine, the exceptions following this don't apply.
It's an unchecked coincidence in a highly complex system.
That may be the best answer you'll get regarding why uninitialized memory in your computer is showing you the pattern you see.
See also...
The c++ statement new int allocates memory from the heap but it doesn't initialize it. So whatever was on the heap or memory from before is being read. You have to do int *b = new int(0) to initialize what b is pointing to with 0.
I've checked myself, I wrote a program like this
int main() {
int i;
cout << i;
return 0;
}
I ran the program a few times and the result was same all the time, zero.
I've tried it in C and the result was the same.
But my textbook says
If you don’t initialize an variable that’s defined
inside a function, the variable value remain undefined.That means the element takes on
whatever value previously resided at that location in memory.
How's this possible when the program always assign a free memory location to a variable? How could it be something other than zero(I assume that default free memory value is zero)?
How's this possible when the program always assign a free memory
location to a variable? How could it be something rather than zero?
Let's take a look at an example practical implementation.
Let's say it utilizes stack to keep local variables.
void
foo(void)
{
int foo_var = 42;
}
void
bar(void)
{
int bar_var;
printf("%d\n", bar_var);
}
int
main(void)
{
bar();
foo();
bar();
}
Totally broken code above illustrates the point. After we call foo, certain location on the stack where foo_var was placed is set to 42. When we call bar, bar_var occupies that exact location. And indeed, executing the code results in printing 0 and 42, showing that bar_var value cannot be relied upon unless initialized.
Now it should be clear that local variable initialisation is required. But could main be an exception? Is there anything which could play with the stack and in result give us a non-zero value?
Yes. main is not the first function executed in your program. In fact there is tons of work required to set everything up. Any of this work could have used the stack and leave some non-zeros on it. Not only you can't expect the same value on different operating systems, it may very well suddenly change on the very system you are using right now. Interested parties can google for "dynamic linker".
Finally, the C language standard does not even have the term stack. Having a "place" for local variables is left to the compiler. It could even get random crap from whatever happened to be in a given register. It really can be totally anything. In fact, if an undefined behaviour is triggered, the compiler has the freedom to do whatever it feels like.
If you don’t initialize an variable that’s defined inside a function, the variable value remain undefined.
This bit is true.
That means the element takes on whatever value previously resided at that location in memory.
This bit is not.
Sometimes in practice this will occur, and you should realise that getting zero or not getting zero perfectly fits this theory, for any given run of your program.
In theory your compiler could actually assign a random initial value to that integer if it wanted, so trying to rationalise about this is entirely pointless. But let's continue as if we assumed that "the element takes on whatever value previously resided at that location in memory"…
How could it be something rather than zero(I assume that default free memory value is zero)?
Well, this is what happens when you assume. :)
This code invokes Undefined Behavior (UB), since the variable is used uninitialized.
The compiler should emit a warning, when a warning flag is used, like -Wall for example:
warning: 'i' is used uninitialized in this function [-Wuninitialized]
cout << i;
^
It just happens, that at this run, on your system, it had the value of 0. That means that the garbage value the variable was assigned to, happened to be 0, because the memory leftovers there suggested so.
However, notice that, kernel zeroes appear relatively often. That means that it is quite common that I can get zero as an output of my system, but it is not guaranteed and should not be taken into a promise.
Static variables and global variables are initialized to zero:
Global:
int a; //a is initialized as 0
void myfunc(){
static int x; // x is also initialized as 0
printf("%d", x);}
Where as non-static variables or auto variables i.e. the local variables are indeterminate (indeterminate usually means it can do anything. It can be zero, it can be the value that was in there, it can crash the program). Reading them prior to assigning a value results in undefined behavior.
void myfunc2(){
int x; // value of x is assigned by compiler it can even be 0
printf("%d", x);}
It mostly depends on compiler but in general most cases the value is pre assumed as 0 by the compliers
I just stumbled upon a behavior which surprised me:
When writing:
int x = x+1;
in a C/C++-program (or even more complex expression involving the newly created variable x) my gcc/g++ compiles without errors. In the above case X is 1 afterwards. Note that there is no variable x in scope by a previous declaration.
So I'd like to know whether this is correct behaviour (and even might be useful in some situation) or just a parser pecularity with my gcc version or gcc in general.
BTW: The following does not work:
int x++;
With the expression:
int x = x + 1;
the variable x comes into existence at the = sign, which is why you can use it on the right hand side. By "comes into existence", I mean the variable exists but has yet to be assigned a value by the initialiser part.
However, unless you're initialising a variable with static storage duration (e.g., outside of a function), it's undefined behaviour since the x that comes into existence has an arbitrary value.
C++03 has this to say:
The point of declaration for a name is immediately after its complete declarator (clause 8) and before its initializer (if any) ...
Example:
int x = 12;
{ int x = x; }
Here the second x is initialized with its own (indeterminate) value.
That second case there is pretty much what you have in your question.
It's not, it's undefined behavior.
You're using an uninitialized variable - x. You get 1 out of pure luck, anything could happen.
FYI, in MSVS I get a warning:
Warning 1 warning C4700: uninitialized local variable 'i' used
Also, at run-time, I get an exception, so it's definitely not safe.
int x = x + 1;
is basically
int x;
x = x + 1;
You have just been lucky to have 0 in x.
int x++;
however is not possible in C++ at a parser level! The previous could be parsed but was semantically wrong. The second one can't even be parsed.
In the first case you simply use the value already at the place in memory where the variable is. In your case this seems to be zero, but it can be anything. Using such a construct is a recipe for disaster and hard to find bugs in the future.
For the second case, it's simply a syntax error. You can not mix an expression with a variable declaration like that.
The variable is defined from the "=" on, so it is valid and when it is globally defined, it is initialized as zero, so in that case it is defined behavior, in others the variable was unintialized as as such still is unitialized (but increased with 1).
Remark that it still is not very sane or useful code.
3.3.1 Point of declaration 1 The point of declaration for a name is immediately after its complete declarator (clause 8) and before its
initializer (if any), except as noted below. [ Example: int x = 12; {
int x = x; } Here the second x is initialized with its own
(indeterminate) value. —end example ]
The above states so and should have indeterminate value, You are lucky with 1.
Your code has two possiblities:
If x is a local variable, you have undefined behavior, since you use the value of an object before its lifetime begins.
If x has static or thread-local lifetime, it is pre-initialized to zero, and your static initialization will reliably set it to 1. This is well-defined.
You may also wish to read my answer that covers related cases, including variables of other types, and variables which are written to before their initialization is completed
This is undefined behaviour and the compiler should at least to issue a warning. Try to compile using g++ -ansi .... The second example is just a syntax error.