By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
454,379 Members | 1,602 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 454,379 IT Pros & Developers. It's quick & easy.

int var declared in "for" not local?

P: n/a
I'm getting a bizarre error with this code:

...
case WM_COMMAND:
{
switch (LOWORD(wParam)) // switch (control ID)
{
...
case IDC_RAIN_ENABLE_SIMPLE:
{
if (BN_CLICKED == HIWORD(wParam))
{
for ( int i = 0 ; i < 11 ; +i)
{
ShowWindow(GetDlgItem(hDlg, RainControls[i]), SW_SHOW);
}

for ( int i = 11 ; i < 25 ; +i) // !!! ERROR !!! ERROR !!!
ERROR !!!
{
ShowWindow(GetDlgItem(hDlg, RainControls[i]), SW_HIDE);
}
}
break;
}
...
break;
}
...
break;
}
...
break;
...
My compiler here at work (MS VC++ 6.0) balks at the line marked
"ERROR" above. It says this is a "redefinition" of i .
How can this be? Isn't i local to each for statement? Doesn't
the closing curly brace of the "0 to 10" for statement make i
go out of scope? So defining a new i in the next for statement
should be perfectly ok, shouldn't it?

Am I missing something here, or is this a bug in MS VC++ 6.0?

--
Puzzled,
Robbie Hatley
lone wolf intj at pac bell dot net
Dec 16 '05 #1
Share this Question
Share on Google+
12 Replies


P: n/a

Robbie Hatley wrote:
I'm getting a bizarre error with this code:

...
case WM_COMMAND:
{
switch (LOWORD(wParam)) // switch (control ID)
{
...
case IDC_RAIN_ENABLE_SIMPLE:
{
if (BN_CLICKED == HIWORD(wParam))
{
for ( int i = 0 ; i < 11 ; +i)
{
ShowWindow(GetDlgItem(hDlg, RainControls[i]), SW_SHOW);
}

for ( int i = 11 ; i < 25 ; +i) // !!! ERROR !!! ERROR !!!
ERROR !!!
{
ShowWindow(GetDlgItem(hDlg, RainControls[i]), SW_HIDE);
}
}
break;
}
...
break;
}
...
break;
}
...
break;
...
My compiler here at work (MS VC++ 6.0) balks at the line marked
"ERROR" above. It says this is a "redefinition" of i .
How can this be? Isn't i local to each for statement? Doesn't
the closing curly brace of the "0 to 10" for statement make i
go out of scope? So defining a new i in the next for statement
should be perfectly ok, shouldn't it?

Am I missing something here, or is this a bug in MS VC++ 6.0?


It's a non-conformancy in VC++ 6. Their standard solution is to upgrade
to VC.NET, which might be expensive or otherwise undesirable, to wrap
for loops in a set of curly braces, which is ugly, or to use a macro:

#define for if(0);else for

Cheers! --M

Dec 16 '05 #2

P: n/a

"mlimber" <ml*****@gmail.com> wrote in message

news:11*********************@g43g2000cwa.googlegro ups.com...

Robbie Hatley wrote:
...
My compiler here at work (MS VC++ 6.0) balks at the line marked
"ERROR" above. It says this is a "redefinition" of i .
How can this be? Isn't i local to each for statement? ...
It's a non-conformancy in VC++ 6.


I see! Thanks for the info. Looks like MS is handling
var. decls. in for parens. the same way as some old
implimentations of C did, if I remember correctly.
(Wasn't this the way K&R C did it?) I'll just have to
remember that the scope of i is the block ENCLOSING
the for statement.

I think the way I'll handle that is like so:

case BLAT:
{
int i;
for ( i = 0; i < 11; ++i )
{
DoSomeStuff(Splat[i]);
}
for ( i = 11; i < 25; ++i )
{
DoOtherStuff(Splat[i]);
}
break;
}

Yes, that works.

--
Cheers!
Robbie Hatley
lone wolf intj at pac bell dot net
Dec 16 '05 #3

P: n/a
mlimber <ml*****@gmail.com> wrote:

Robbie Hatley wrote:
for ( int i = 0 ; i < 11 ; +i)
{
ShowWindow(GetDlgItem(hDlg, RainControls[i]), SW_SHOW);
}

for ( int i = 11 ; i < 25 ; +i) // !!! ERROR !!! ERROR !!!
ERROR !!!
{
ShowWindow(GetDlgItem(hDlg, RainControls[i]), SW_HIDE);
}

My compiler here at work (MS VC++ 6.0) balks at the line marked
"ERROR" above. It says this is a "redefinition" of i .
How can this be? Isn't i local to each for statement? Doesn't
the closing curly brace of the "0 to 10" for statement make i
go out of scope? So defining a new i in the next for statement
should be perfectly ok, shouldn't it?

Am I missing something here, or is this a bug in MS VC++ 6.0?


It's a non-conformancy in VC++ 6. Their standard solution is to upgrade
to VC.NET, which might be expensive or otherwise undesirable, to wrap
for loops in a set of curly braces, which is ugly, or to use a macro:

#define for if(0);else for


Additionally, even with VC.NET 2003, you must pass a commandline option
to the compiler to enforce this rule:

/Zc:arg1[,arg2] C++ language conformance, where arguments can be:
forScope - enforce Standard C++ for scoping rules
wchar_t - wchar_t is the native type, not a typedef

--
Marcus Kwok
Dec 16 '05 #4

P: n/a
Marcus Kwok wrote:

Additionally, even with VC.NET 2003, you must pass a commandline option
to the compiler to enforce this rule:

/Zc:arg1[,arg2] C++ language conformance, where arguments can be:
forScope - enforce Standard C++ for scoping rules
wchar_t - wchar_t is the native type, not a typedef


Well, yes and no. If you don't set that option, the VC++ 2003 compiler
will try to figure out what you mean. I.e. if you do this:

for (int i = 0; i < 10; ++i) a[i] = i;
cout << i << endl;

then the output will be "10", but if you do this:

for (int i = 0; i < 10; ++i) a[i] = i;
int i = 37;
cout << i << endl;

then the output will be "37".

--
Mike Smith
Dec 16 '05 #5

P: n/a
Mike Smith <mi*****************@acm.org> wrote:
Marcus Kwok wrote:

Additionally, even with VC.NET 2003, you must pass a commandline option
to the compiler to enforce this rule:

/Zc:arg1[,arg2] C++ language conformance, where arguments can be:
forScope - enforce Standard C++ for scoping rules
wchar_t - wchar_t is the native type, not a typedef
Well, yes and no. If you don't set that option, the VC++ 2003 compiler
will try to figure out what you mean. I.e. if you do this:

for (int i = 0; i < 10; ++i) a[i] = i;
cout << i << endl;

then the output will be "10"


Yes, though this is not standard C++.
but if you do this:

for (int i = 0; i < 10; ++i) a[i] = i;
int i = 37;
cout << i << endl;

then the output will be "37".


Yes. I get a warning, but the output is still 37 as you say:

#include <iostream>

int main()
{
int a[10];

for (int i = 0; i < 10; ++i) { // <-- line 7
a[i] = i;
}

int i = 37; // <-- line 11

std::cout << i << '\n'; // <-- line 13

return 0;
}

test.cpp(13) : warning C4288: nonstandard extension used : 'i' : loop
control variable declared in the for-loop is used outside the for-loop
scope; it conflicts with the declaration in the outer scope
test.cpp(11) : definition of 'i' used
test.cpp(7) : definition of 'i' ignored
With /Zc:forScope:

test.cpp(13) : warning C4258: 'i' : definition from the for loop is
ignored; the definition from the enclosing scope is used
test.cpp(7) : definition of 'i' ignored
test.cpp(11) : definition of 'i' used

--
Marcus Kwok
Dec 17 '05 #6

P: n/a
On Fri, 16 Dec 2005 20:05:09 GMT, "Robbie Hatley"
<bo*********@no.spam.com> wrote:
I think the way I'll handle that is like so:

case BLAT:
{
int i;
for ( i = 0; i < 11; ++i )
{
DoSomeStuff(Splat[i]);
}
for ( i = 11; i < 25; ++i )
{
DoOtherStuff(Splat[i]);
}
break;
}

Yes, that works.


The official Microsoft workaround is:

#define for if(0);else for

http://support.microsoft.com/default...b;en-us;167748
Dec 17 '05 #7

P: n/a
"Roland Pibinger" <rp*****@yahoo.com> wrote:
The official Microsoft workaround [for the "variables
declared inside for-loop parentheses are not local" bug]
is:

#define for if(0);else for

http://support.microsoft.com/default...b;en-us;167748


Ok, thanks for the info,

However, I don't think I'll use that particular fix
globally, because the program I'm maintaining at work
is about 325,000 lines of poorly-written C code, converted
to C++ (by me), with another 25,000 lines of C++ code added
in over a couple years by three different maintainance
programmers (including myself). I'm afraid somewhere,
someone has actually used-and-depended-on the "non-local-for-
loop-variables" effect. If they did this:

int Borogoves(int Brillig[], int Gyre, int Gimble)
{
for (int Mimsy = 0; Mimsy < Gimble; ++Mimsy)
{
if (Gyre == Brillig[Mimsy]) break;
}
return Mimsy;
}

and if I did this:

// in main.h (included in all *.cpp files):
#define for if(0);else for

that would break Borogoves() . It would no longer
even compile.

But I'll keep the workaround in mind for use in smaller
files with few for loops.

--
Robbie Hatley
Tustin, CA, USA
email: lonewolfintj at pacbell dot net
web: home dot pacbell dot net slant earnur slant
Dec 18 '05 #8

P: n/a
Robbie Hatley wrote:

However, I don't think I'll use that particular fix
globally, because the program I'm maintaining at work
is about 325,000 lines of poorly-written C code, converted
to C++ (by me),
What do you mean by "converted to C++" exactly ?
Renaming .c files to .cpp and changing malloc to new,
is a great way to produce unmaintainable code.

It's probably too late now, but IMHO it is better to leave
C files as C and write new stuff as C++ (and link the two
together, which is simple) , until you are ready to fully
re-write a particular unit as good C++.
with another 25,000 lines of C++ code added
in over a couple years by three different maintainance
programmers (including myself). I'm afraid somewhere,
someone has actually used-and-depended-on the
"non-local-for-loop-variables" effect. If they did this:

int Borogoves(int Brillig[], int Gyre, int Gimble)
{
for (int Mimsy = 0; Mimsy < Gimble; ++Mimsy)
{
if (Gyre == Brillig[Mimsy]) break;
}
return Mimsy;
}

and if I did this:

// in main.h (included in all *.cpp files):
#define for if(0);else for

that would break Borogoves() . It would no longer
even compile.


Then you would get compiler errors in every place that
relied on the non-standard behaviour, and you could quickly
fix it all.

However a more subtle problem is:

int foo()
{
int mimsy = 3;
if ( bar() )
{
for (int mimsy = 0; mimsy != 5; ++mimsy)
qux();
return mimsy;
}
}

where the behaviour would silently change with this 'fix'.
Perhaps you could set your compiler to generate assembly
output, then make the fix and do a diff on the generated
assembly. You'd need to be heavily optimising of course,
so that it skips out the extra "if..else" .

Dec 19 '05 #9

P: n/a
"Old Wolf" <ol*****@inspire.net.nz> wrote:
Robbie Hatley wrote:

However, I don't think I'll use that particular fix
globally, because the program I'm maintaining at work
is about 325,000 lines of poorly-written C code, converted
to C++ (by me),
What do you mean by "converted to C++" exactly ?
Renaming .c files to .cpp and changing malloc to new,
is a great way to produce unmaintainable code.


Oh believe me when I tell you, this code I'm maintaining
was plenty "unmaintainable" as a C program, and continues
to be equally "unmaintainable" as a C++ program. Which
makes maintaining it loads of <sarcasm>fun</sarcasm>.

I didn't change any malloc to new. There weren't any,
actually. Lots of GlobalAlloc(), which is the Windows
version of the same thing. I left those alone.

The reasons I converted the program to C++ were two:
1. To get the much stronger typing of MS-VC++ 6's C++
compiler, in place of the weak typing of it's C compiler.
(Which involved fixing about 5000 compiler errors and
10000 linker errors after the switch, due to the author's
mind-boglingly sloppy handling of data types.)
2. To allow use of the C++ STL, especially maps and deques.
(We were adding features that needed maps of structs,
keyed by ints, where the structs contained deques. Doing
that in C would have been unwieldy, but in C++, it was
a breeze.)
It's probably too late now
Waaaaaaay too late.
but IMHO it is better to leave C files as C and write new
stuff as C++ (and link the two together, which is simple)
Why? See above under "stronger typing". After converting
to C++ and fixing the many thousands of compiler and linker
errors which immediately cropped up, my co-workers and I
found that many of the bugs which customers and field-service
reps had be complaining about over the years mysteriously
vanished overnight. The key was, taking the time to figure
out why each data-type conflict was occuring, and to try to
solve it at its source, rather than bandaid it with a
typecast, which is a good way to hide bugs rather than fixing
them.

I agree that if you have a WELL-WRITTEN C program, and
want to add C++ stuff to it (STL, containers, algorithms,
templates, classes, polymorphism, whatever), it's best to
leave the C files alone, and write the new stuff as separate
C++ files and just link 'm in. (Taking measures to ensure
stuff links right, of course, which involves heavy use of
"extern C" among other things.)

However, this particular C program was NOT well-written,
so converting the whole #! to C++ actually helped.
until you are ready to fully re-write a particular unit as
good C++.
That's not going to happen in the life of this program.
The money's not there. The bosses want bug fixes and new
features, not re-factoring.

I wrote about the possible use of the "non-local for vars"
in the program, and my fear of breaking such uses, and
Old Wolf replied:
Then you would get compiler errors in every place that
relied on the non-standard behaviour, and you could quickly
fix it all.
Maybe, maybe not. As you later admited in the same post:
However a more subtle problem is:

int foo()
{
int mimsy = 3;
if ( bar() )
{
for (int mimsy = 0; mimsy != 5; ++mimsy)
qux();
return mimsy;
}
}

where the behaviour would silently change with this 'fix'.
Which is exactly why I'm not going to impliment MS's
recommended fix globally. Like I say, I may use it
in some individual files with few for statements, where
I can clearly see it won't break anything.
Perhaps you could set your compiler to generate assembly
output, then make the fix and do a diff on the generated
assembly. You'd need to be heavily optimising of course,
so that it skips out the extra "if..else" .


Unless one knows i386 assembly rather well, I don't
see how that would help. Two versions of a C++ program
that generate different assembly outputs may be functionally
different... or they may be functionally the same. I don't
know assembly language well enough to tell the difference.
I'd be squinting, mumbling "PUSH here, POP there, MOV here,
ADD there, and what's this NOP doing? Oh, right, nothing...
Um... HELP!!!" No, I think I'll stick to C++.

--
Cheers!
Robbie Hatley
Tustin, CA, USA
email: lonewolfintj at pacbell dot net
web: home dot pacbell dot net slant earnur slant
Dec 19 '05 #10

P: n/a
Robbie Hatley wrote:
"Old Wolf" <ol*****@inspire.net.nz> wrote:
Perhaps you could set your compiler to generate assembly
output, then make the fix and do a diff on the generated
assembly. You'd need to be heavily optimising of course,
so that it skips out the extra "if..else" .


Unless one knows i386 assembly rather well, I don't
see how that would help. Two versions of a C++ program
that generate different assembly outputs may be functionally
different...


The same source code would generate the same assembly each
time it's compiled. If this 'fix' is the only difference, it seems
plausible to me that the assembly generated would be the same
in every case, or similar enough that perusing the results of a 'diff'
will tell you which changes made no difference and which ones
suddenly referenced a different variable.

Dec 19 '05 #11

P: n/a
Robbie Hatley wrote:

The reasons I converted the program to C++ were two:
1. To get the much stronger typing of MS-VC++ 6's C++
compiler, in place of the weak typing of it's C compiler.
(Which involved fixing about 5000 compiler errors and
10000 linker errors after the switch, due to the author's
mind-boglingly sloppy handling of data types.)


A good reason. While we're on this topic, one way that has
succeeded for me in the past is to compile the source with
GCC, and use the free gnu-win32 package to provide the
windows headers so that it will compile. (Or even write your
own header if the project doesn't use much winapi stuff).
GCC is an excellent lint tool :)

Dec 19 '05 #12

P: n/a
Old Wolf wrote:
Robbie Hatley wrote:

The reasons I converted the program to C++ were two:
1. To get the much stronger typing of MS-VC++ 6's C++
compiler, in place of the weak typing of it's C compiler.
(Which involved fixing about 5000 compiler errors and
10000 linker errors after the switch, due to the author's
mind-boglingly sloppy handling of data types.)

A good reason. While we're on this topic, one way that has
succeeded for me in the past is to compile the source with
GCC, and use the free gnu-win32 package to provide the
windows headers so that it will compile. (Or even write your
own header if the project doesn't use much winapi stuff).
GCC is an excellent lint tool :)


You probably well aware of this already, but I've seen code using C++
objects inside memory allocated using malloc() and free(). Unfortunately
, as far as I know it still exists along with all the hanging allocated
memory that it causes, not to mention no constructor calls! So, good
luck and take great care, as the task you're undertaking is fraught with
difficulties that can catch the best of us, (I can only hope that I'm
one of the best).

JB
Dec 20 '05 #13

This discussion thread is closed

Replies have been disabled for this discussion.