Reputation: 2580
#include<stdio.h>
int main()
{
int i = 10;
printf("0 i %d %p\n",i,&i);
if (i == 10)
goto f;
{
int i = 20;
printf("1 i %d\n",i);
}
{
int i = 30;
f:
printf("2 i %d %p\n",i,&i); //statement X
}
return 0;
}
Output:
[test]$ ./a.out
0 i 10 0xbfbeaea8
2 i 134513744 0xbfbeaea4
I have difficulty in understanding how statement X works?? As you see the output it is junk. It should rather say i not declared??
Upvotes: 3
Views: 4015
Reputation: 33014
That's because goto
skips the shadowing variable i
's initialization.
This is one of the minor nuances of the differences between C and C++. In strict C++ go to crossing variable initialization is an error, while in C it's not. GCC also confirms this, when you compile with -std=c11 it allows while with std=c++11 it complains: jump to label 'f' crosses initialization of 'int i'.
From C99:
A goto statement shall not jump from outside the scope of an identifier having a variably modified type to inside the scope of that identifier.
VLAs are of variably modified type. Jumps inside a scope not containing VM types are allowed.
From C++11 (emphasis mine):
A program that jumps from a point where a variable with automatic storage duration is not in scope to a point where it is in scope is ill-formed unless the variable has scalar type, class type with a trivial default constructor and a trivial destructor, a cv-qualified version of one of these types, or an array of one of the preceding types and is declared without an initializer.
Upvotes: 10
Reputation: 6421
The problem is that your goto
is skipping the assignment to the second i
, which shadows (conceals) the first i
whose value you've set, so you're printing out an uninitialized variable.
You'll get a similar wrong answer from this:
#include<stdio.h>
int main()
{
int i = 10; /* First "i" */
printf("0 i %d %p\n",i,&i);
{ /* New block scope */
int i; /* Second "i" shadows first "i" */
printf("2 i %d %p\n",i,&i);
}
return 0;
}
Three lessons: don't shadow variables; don't create blocks ({ ... }
) for no reason; and turn on compiler warnings.
Just to clarify: variable scope is a compile-time concept based on where variables are declared, not something that is subject to what happens at runtime. The declaration of i
#2 conceals i
#1 inside the block that i
#2 is declared in. It doesn't matter if the runtime control path jumps into the middle of the block — i
#2 is the i
that will be used and i
#1 is hidden (shadowed). Runtime control flow doesn't carry scope around in a satchel.
Upvotes: 0
Reputation: 931
In the first printf statement, you accessed the i in address 0xbfbeaea8 which was declared and initialized in the statement int i = 10;
Once you hit the goto f;
statement, you are in the scope of the 2nd i, which is declared at this point and resides in address 0xbfbeaea4 but which is not initialized as you skipped the initialization statement.
That's why you were getting rubbish.
Upvotes: 1
Reputation: 2457
From the output, it is clear that the address of 'i's are unique, since they are declared in different scopes.
0 i 10 0xbfbeaea8
2 i 134513744 0xbfbeaea4
how statement X works?? As you see the output it is junk. It should rather say I not declared??
i
is also declared in the local scope of statement x
but the initialization of i
to 30 is skipped because of goto
statement. Therefore the local variable i
contains a garbage value.
Upvotes: 2
Reputation: 2373
The i
you print in this printf("2 i %d %p\n",i,&i);
statement, is not the i
which value was 10
in if
statement, and as you skip this int i = 30;
statement with goto
you print garbage. This int i = 30;
is actual definition of the i
that would be printed, i.e. where compiler allocates room and value of i
.
Upvotes: 0
Reputation: 3609
My suggestion to understand somewhat complex code is to strip out, one by one, all "unnecessary" code and leave the bare problem. How do you know what's unnecessary? Initially, when you're not fluent with the language, you'll be removing parts of the code at random, but very quickly you'll learn what's necessary and what is not.
Give it a try: my hint is to start removing or commenting out the "goto" statement. Recompile and, if there are no errors, see what changed when you run the program again.
Another suggestion would be: try to recreate the problem "from scratch": imagine you are working on a top-secret project and you cannot show any single line of code to anyone, let alone post on Stack Overflow. Now, try to replicate the problem by rewriting equivalent source code, that would show the same behaviour.
As they say, "asking the right question is often solving half the problem".
Upvotes: 0
Reputation: 6116
When control reaches the third block, i
is declared for the compiler, hence i
represents some memory address therefore compiler tries to read it again. But since i
has now become out-of-scope, you cannot be sure that it will contain the same value what it originally had.
Upvotes: 0