20

I noticed that the scope rules of the for loop are different for C and C++.
For example, the code below is legal in the C compiler, but not legal in the C++ compiler.

for (int i = 0; i < 10; ++i) {
    int i = 5;
}

The above code is valid in C, but gives a redefinition error in C++.
My guess is that the C compiler treats the loop as if there is another scope inside the loop like below.

for (int i = 0; i < 10; ++i) {
    {
        int i = 5;
    }
}

Why does the C compiler allow a second variable with the same name to be defined in the scope of the loop? Is there any particular reason or advantage for doing this?

Jorengarenar
  • 2,705
  • 5
  • 23
  • 60
east1000
  • 1,240
  • 1
  • 10
  • 30
  • to let C compiler be a bit simpler? – tstanisl Sep 15 '21 at 10:43
  • 1
    Do you have a use case? It seems pretty bug inducing to be able to do this. Which is maybe why C++ opted out of allowing it. – StoryTeller - Unslander Monica Sep 15 '21 at 10:45
  • 2
    I'd add `-Wshadow -Werror` when compiling both C and C++ – Ted Lyngmo Sep 15 '21 at 10:46
  • I agree with the C++ compiler: there is no use for this; use another name. But it is syntactically correct. – Paul Ogilvie Sep 15 '21 at 10:47
  • IIRC, `i` is out-of scope after the `for()` loop. Early `for (int i = 0; ....` implementations sometimes allowed this. – chux - Reinstate Monica Sep 15 '21 at 10:58
  • 2
    All C++ standards, in the section concerned with the `for` statement, have a clause that requires the scope of all variables in the *for-init-statement* (`int i = 0;` in your example) to extend to the end of the `for` statement. That prevents declaring those variables again within the `for` statement. All C standards do NOT have an equivalent clause (in the section concerned with the `for` statement, or anywhere else) - which allows (doesn't prevent) redeclaring a variable in the block of the `for` loop. Whether one or the other approach gives an advantage - that's a matter of opinion. – Peter Sep 15 '21 at 11:00
  • It would be useful to know what compiler and version you are using. That would help revealing what version of the standard of the language you are using :) – Antonio Vázquez Blanco Sep 15 '21 at 11:11
  • 2
    @AntonioVázquezBlanco: I'm pretty sure this is consistent across all C standards, consistent across all C++ standards, yet different between C and C++. This change between C and C++ is only possible because it was introduced early in the standardization of C++ – MSalters Sep 15 '21 at 11:17
  • 1
    I expect this is just due to the history of language development. At some time, somebody thought “Hey, it would be nice if we could declare new variables inside a `for` statement, right where we need them, and their scope ended with the statement, so they would not accidentally be used later.” Then people started using this. But there was no restriction on declaring the same name inside the loop, and sometimes people did that accidentally, hiding the declaration inside the `for` even though they did not want to. So C++ added the rule prohibiting redeclarations… – Eric Postpischil Sep 15 '21 at 11:26
  • 1
    … The rule may not have been added to C because there are difficulties in adding a rule to an old language if it breaks already existing code. – Eric Postpischil Sep 15 '21 at 11:27
  • Notice that the C++ rule **predates** the rule in C. – Antti Haapala -- Слава Україні Sep 15 '21 at 12:08

1 Answers1

17

As far as standards go, for loop scopes are indeed defined differently in C and in C++. In C they are defined as follows:

6.8.5.3 The for statement

The statement

for ( clause-1 ; expression-2 ; expression-3 ) statement

behaves as follows: ...

with no specific reference given to limitations on variable declarations inside the statement. The top-level description of loops ("iteration statements" in the standard) specifies:

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.

as you've hinted in your question, code like:

for (int i = 0; i < 10; ++i)
    int i = 5;

where a new block is not declared (notice the missing { } surrounding the redeclaration) - is not valid code.


Whereas in C++, there is a specific reference to redeclaration of loop variables:

8.6 Iteration statements specify looping ... 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.


As it relates to rationale - likely C++ just added the restriction as an improvement to language semantics, indeed redeclaring a variable this way is usually a bug.

Arguably, this restriction is appropriate in C as well - but adding this restriction to the C standard would break backwards compatibility with existing code and is unlikely to happen.

Daniel Kleinstein
  • 5,262
  • 1
  • 22
  • 39