简体   繁体   中英

Re-declaring variable inside for loop in C

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?

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 of init-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.

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

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.

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 .

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?

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM