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.
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
andwhile
statements6.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
I think the code is correct. IMO, the issue is with the braces. Note that the for statement is defined as:
for ( for-init-statement; condition; expression ) statement
The loop body does not have braces, they are added when using a compound statement. But a compound statement adds its own declarative region, so the inner declaration should not have a conflict with the for-init-statement
.
The following code compiles ok with clang and G++ (note the double braces):
for (int *it = a1, *end = a1+1; it != end; ++it) {{
//...
bool *jt = a2, *end = a2+1;
//...
}}
My guess is that the clang compiler tries to optimize as if the loop were defined as:
for ( for-init-statement; condition; expression ) { statement-seq }
With the suble change in meaning: both declarative regions are fused together.
On second though, even it no braces are used at all:
for (int x=0; ;)
char x;
It should compile correctly. From C++ draft 6.5, par. 2:
The substatement in an iteration-statement implicitly defines a block scope.
So the char x;
by itself defines (implicitly) a block scope, and no conflicting declarations should happen.
The current version of the standard is clear on this:
6.5 Iteration statements [stmt.iter]
2 - The substatement in an iteration-statement [e.g., a
for
loop] implicitly defines a block scope (3.3) which is entered and exited each time through the loop.
C has a similar rule:
6.8.5 Iteration statements
Semantics5 - 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.
Some, generally older compiler makes variables declared in for loops visible outside the scope of the loop.
To make all the compilers behave using the newer ( and better ) way declare a macro like this:
// In older compilers, variables declared in a for loop statement
// are in the scope of the code level right outside the for loop.
// Newer compilers very sensibly limit the scope to inside the
// loop only. For compilers which don't do this, we can spoof it
// with this macro:
#ifdef FOR_LOOP_VARS_NEED_LOCAL_SCOPE
#define for if(0); else for
#endif
Then for each compiler that has the older behavior define FOR_LOOP_VARS_NEED_LOCAL_SCOPE. For example here is how you would do it for MSVC < 8:
#ifdef _MSC_VER
#if _MSC_VER < 1400 // earlier than MSVC8
#define FOR_LOOP_VARS_NEED_LOCAL_SCOPE
#endif
#endif
I'm a bit late to the party here, but I think this is disallowed most clearly by this passage in the C++11 standard:
3.3.3 Block scope [basic.scope.local]
4 - Names declared in the for-init-statement, the for-range-declaration, and in the condition of if, while, for, and switch statements are local to the if, while, for, or switch statement (including the controlled statement), and shall not be redeclared in a subsequent condition of that statement nor in the outermost block (or, for the if statement, any of the outermost blocks) of the controlled statement; see 6.4.
来源:https://stackoverflow.com/questions/12351460/redeclaration-of-a-variable-in-a-for-loop-in-c