Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Redeclaration of a variable in a for-loop in C++

When trying to compile the following (simplified) code for multiple platforms, I found that it was failing on some, namely IBM's xlC_r. Further investigation has found that it also fails on comeau and clang. It compiles successfully with g++ and Solaris's CC.

Here is the code:

int main()
{
    int a1[1];
    bool a2[1];

    for (int *it = a1, *end = a1+1; it != end; ++it) {
        //...
        bool *jt = a2, *end = a2+1;
        //...
    }
}

xlC_r error:

"main.cpp", line 8.25: 1540-0400 (S) "end" has a conflicting declaration.
"main.cpp", line 6.25: 1540-0425 (I) "end" is defined on line 6 of "main.cpp".

clang error:

main.cpp:8:25: error: redefinition of 'end' with a different type
        bool *jt = a2, *end = a2+1;
                        ^
main.cpp:6:25: note: previous definition is here
    for (int *it = a1, *end = a1+1; it != end; ++it) {
                        ^

comeau error:

"ComeauTest.c", line 8: error: "end", declared in for-loop initialization, may not
          be redeclared in this scope
          bool *jt = a2, *end = a2+1;
                          ^

The question is why is this an error?

Looking through the 2003 standard, it says the following (6.5.3):

The for statement
    for ( for-init-statement; condition; expression ) 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 condition

Here there are no names declared in condition.

Further, it says (6.5.1):

When the condition of a while statement is a declaration, the scope
of the variable that is declared extends from its point of declaration
(3.3.1) to the end of the while statement. A while statement of the form
    while (T t = x) statement
is equivalent to
    label:
    {
        T t = x;
        if (t) {
            statement;
            goto label;
        }
    }

Again, I'm not sure this is relevant, as there is no declaration in the condition. So given the equivalent re-write from 6.5.3, my code should be the same as:

int main()
{
    int a1[1];
    bool a2[1];

    {
        int *it = a1, *end = a1+1;
        while (it != end) {
            //...
            bool *jt = a2, *end = a2+1;
            //...
            ++it;
        }
    }
}

Which obviously would allow end to be re-declared.

like image 654
Daryl Avatar asked Sep 10 '12 12:09

Daryl


People also ask

Can you initialize variables in a for loop in C?

Syntax. The init step is executed first, and only once. This step allows you to declare and initialize any loop control variables.

Can you call variables in a for loop?

Declare the variables outside the loops. When you declare them inside the loop, they go out of scope as soon as the loop ends. You can't "call" a variable.

How do you define multiple variables in a for loop?

Yes, I can declare multiple variables in a for-loop. And you, too, can now declare multiple variables, in a for-loop, as follows: Just separate the multiple variables in the initialization statement with commas. Do not forget to end the complete initialization statement with a semicolon.

What does the variable do in a for loop?

In computer programming, a loop variable is a variable that is set in order to execute some iterations of a "for" loop or other live structure. A loop variable is a classical fixture in programming that helps computers to handle repeated instructions.


1 Answers

The standard is somewhat ambiguous. The code you quote as being equivalent to a while loop implies that there is an inner scope where declarations inside the loop could hide declarations in the condition; however the standard also says (quoting C++11, since I don't have C++03 handy):

6.4/2 The rules for conditions apply both to selection-statements and to the for and while statements

6.4/3 If the name is re-declared in the outermost block of a substatement controlled by the condition, the declaration that re-declares the name is ill-formed.

6.5.3/1 names declared in the for-init-statement are in the same declarative-region as those declared in the condition

which between them imply that the names can't be redeclared.

Older (pre-1998) versions of the language put declarations in the for-init-statement into the declarative region outside the loop. This meant that your code would be valid, but this wouldn't:

for (int i = ...; ...; ...) {...}
for (int i = ...; ...; ...) {...}  // error: redeclaration of i
like image 65
Mike Seymour Avatar answered Sep 26 '22 14:09

Mike Seymour