Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why doesn't the C compiler give a redeclaration error inside a for loop body? [duplicate]

In the C language, if we write this:

for(int i = 0; i < 7; i++)
{
    // for loop Body
}

The scope of variable i is inside the for loop body. It is OK.

But, if I write this:

for(int i = 0; i < 7; i++)
{
    long int i = 1; // Redeclaration of i
}

Here, the variable i is declared again inside the loop body, yet it successfully compiles and runs in C.

But, in C++, the compiler gives a "redeclaration of 'long int i'" error.

So, why doesn't the C compiler give a redeclaration error? Is it a compiler bug?

like image 996
msc Avatar asked Jul 11 '18 05:07

msc


2 Answers

C++ and C make a distinction here. According to C11 (n1570) §6.8.5 ¶5, emphasis mine:

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.

Which translates to this for a for loop:

{
    declaration 
    while ( expression) {
        statement
        expression ;
    }
}

Anything you put in the statement part can hide whatever is introduced in the declaration. Now, C++(17, n4659) explicitly says something similar at [stmt.for]/1. But it also goes on to add:

except that names declared in the init-statement are in the same declarative region as those declared in the condition,

So here the second i is indeed an attempt at a re-declaration. The above may sound confusing (names declared in the condidion!?), but the "condition" here is defined like this ([stmt.stmt]/1):

condition:
    expression
    attribute-specifier-seq decl-specifier-seq declarator brace-or-equal-initializer

It's that which allows while loops like this (C++ only):

while (T t = x) statement 

And you may not re-declare t inside the statement of the while loop.


Alternatively, the entire conclusion I reach is summarized in [stmt.iter]/3 (thank you @T.C.):

If a name introduced in an init-statement or for-range-declaration is redeclared in the outermost block of the substatement, the program is ill-formed.

like image 179
StoryTeller - Unslander Monica Avatar answered Oct 09 '22 15:10

StoryTeller - Unslander Monica


First of all, there is no re-declaration inside the loop. Inside the loop body. i is defined every time the loop is entered, and the scope is only till the loop body.

Once the loop finishes the iteration, the variable does not exist anymore. (First quote)

That being said, what you are seeing is a result of shadowing. (Second quote)

Quoting C11,

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. [...]

and,

[...] 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.

like image 27
Sourav Ghosh Avatar answered Oct 09 '22 14:10

Sourav Ghosh