Reputation: 34648
I have compiled following program using gcc prog.c -Wall -Wextra -std=gnu11 -pedantic
command on GCC compiler. I wondered, it is working fine without any warnings or errors.
#include <stdio.h>
int main(void)
{
for (int i = 0; i == 0; i++)
{
printf("%d\n", i);
long int i = 1; // Why doesn't redeclaration error?
printf("%ld\n", i);
}
}
Why compiler doesn't generate redeclaration variable i
error?
Upvotes: 6
Views: 2390
Reputation:
For further verification i checked this code in visual studio 2008 for the prog.c file. I found that the compiler does give error in the line for (int i = 0; i == 0; i++) . The compiler expects declaration of i to be in the beginning of the program itself. This behavior is correct for a C file. If the declaration is moved to the beginning of the program then there are no errors as expected. All scope related issues are solved.
If i try this code as prog.cpp file, then the compiler does give an error for redeclaration. This is also an expected behavior.
So i conclude this has to do with the gcc compiler, does any flag/parameters that is used for compiling/building the exe results in this behavior for the gcc compiler.
Can rsp post the make file details for further verification?
Upvotes: 0
Reputation: 12679
Why compiler doesn't generate redeclaration variable i error?
From C Standards#6.2.1p4 Scopes of identifiers
Every other identifier has scope determined by the placement of its declaration (in a declarator or type specifier). 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. If the declarator or type specifier that declares the identifier appears inside a block or within the list of parameter declarations in a function definition, the identifier has block scope, which terminates at the end of the associated block. If the declarator or type specifier that declares the identifier appears within the list of parameter declarations in a function prototype (not part of a function definition), the identifier has function prototype scope, which terminates at the end of the function declarator. If an identifier designates two different entities in the same name space, the scopes might overlap. If so, the scope of one entity (the inner scope) will end strictly before the scope of the other entity (the outer scope). Within the inner scope, the identifier designates the entity declared in the inner scope; the entity declared in the outer scope is hidden (and not visible) within the inner scope.
From C standards#6.8.5p5 Iteration statements
An iteration statement is a block whose scope is a strict subset of the scope of its enclosing block. The loop body is also a block whose scope is a strict subset of the scope of the iteration statement.
So, in this code:
for (int i = 0; i == 0; i++)
{
printf("%d\n", i);
long int i = 1; // Why doesn't redeclaration error?
printf("%ld\n", i);
}
the scope of identifier with name i
is overlapping and in this name space, the i
declared in for (int i = 0; i == 0; i++)
has outer scope and the one declared within loop body long int i = 1;
has inner scope.
Within the loop body, after this statement:
long int i = 1;
the i
declared in the outer scope is not visible and printf()
printing the value of i
visible in the inner scope which is 1
.
This behavior is also known as Variable Shadowing which occurs when a variable declared within a certain scope has the same name as a variable declared in an outer scope.
C language allows variable shadowing and that's why the compiler does not throw any error for this. However, in gcc
compiler, if you use -Wshadow
option you will get a warning message - declaration shadows a local variable
.
Upvotes: 0
Reputation: 34648
In C language, the scope of statement
is nested within the scope of for loop init-statement
.
According to Cppreference :
While in C++, the scope of the init-statement and the scope of statement are one and the same, in C the scope of
statement
is nested within the scope ofinit-statement
.
According to stmt:
The for statement
for ( for-init-statement conditionopt ; expressionopt ) statement
is equivalent to
{ for-init-statement while ( condition ) { statement expression ; } }
except that names declared in the for-init-statement are in the same declarative-region as those declared in the condition, and except that a continue in statement (not enclosed in another iteration statement) will execute expression before re-evaluating condition.
Upvotes: 6
Reputation: 30926
From standard §6.8.5.5 (N1570)
An iteration statement is a block whose scope is a strict subset of the scope of its enclosing block. The loop body is also a block whose scope is a strict subset of the scope of the iteration statement.
Emphasis added
Upvotes: 6
Reputation: 16660
You have to set -Wshadow to get warnings on shadowed variables. Variable shadowing is allowed in C.
But this is an edge case. A var declared in the head of a for
construction is not outside the brackets, because it has no scope after the construction.
This is not equivalent:
int i;
for( i = 0; …)
{ … }
// is is still in scope but wouldn't if declared in the head of for
But, it is not inside the brackets, too.
for( i = 0; …)
{
int i; // this would be strange, because i is used before it is declared.
…
}
The best approximative replacement of the code is this:
{
int i;
for( i = 0; …)
{
…
}
} // i loses scope
So it is no redeclaration, but a shadowing declaration inside the loop's body.
Upvotes: 2