Variable declaration and while loops

Z

Zachary Turner

Hello,

This seems like an extremely basic question, and I'm a bit embarassed
that I can't answer it myself.

I just recently started using GCC and tried to type the following
code:

while ((int i = getint()) != 0)
{
/* something */
}

which my compiler has been supporting for a good few years. Under GCC
this doesn't compile. At first it didn't even occur to me that maybe
the code was invalid. I just thought GCC was being stupid. But then
it occurred to me that this probably really isn't valid C++, and that
my compiler has just been breaking the rule. Can anyone shed some
light? Can you declare a variable in a while loop similar to how you
can with a for loop?
 
V

Victor Bazarov

Zachary said:
Hello,

This seems like an extremely basic question, and I'm a bit embarassed
that I can't answer it myself.

I just recently started using GCC and tried to type the following
code:

while ((int i = getint()) != 0)

Drop the "!= 0" part and you'll have a standard construct.
{
/* something */
}

which my compiler has been supporting for a good few years. Under GCC
this doesn't compile. At first it didn't even occur to me that maybe
the code was invalid. I just thought GCC was being stupid. But then
it occurred to me that this probably really isn't valid C++, and that
my compiler has just been breaking the rule. Can anyone shed some
light? Can you declare a variable in a while loop similar to how you
can with a for loop?

No, you cannot. Those are two different statements and they have
different syntax. You can, however, declare/define/initialise an object
in a 'while' or 'if' parentheses, but you cannot do it in an expression.

if (int i = getint())

is valid

if ((int i = getint()) != 0)

is not, although the semantics are the same. (you can replace 'if'
with 'while' above).

V
 
M

Markus Moll

Hi

Zachary Turner schreef:
I just recently started using GCC and tried to type the following
code:

while ((int i = getint()) != 0)
{
/* something */
}

which my compiler has been supporting for a good few years. Under GCC
this doesn't compile. At first it didn't even occur to me that maybe
the code was invalid. I just thought GCC was being stupid. But then
it occurred to me that this probably really isn't valid C++, and that
my compiler has just been breaking the rule. Can anyone shed some
light? Can you declare a variable in a while loop similar to how you
can with a for loop?

Yes, but you may not parenthesize it (a declaration is not an
expression). So, correctly, your code would read:

while(int i = getint())
{
/* something */
}

The condition in an if-, while-, switch- and even in a for-statement may
be a declaration with initialization. In this case, the condition
evaluates to the value of the declared variable, converted to bool.

Markus
 
A

Andre Kostur

Drop the "!= 0" part and you'll have a standard construct.

Personal style: ick. I prefer to explicitly test against 0 when dealing
with ints (I also prefer to explicitly mention NULL when dealing with
pointers too.) If the expression type is bool (or 99.9% of the time
intended to be treated as a bool, such as the void* return of streams.
It's not really intended to be used as a pointer, but it prevents other
unintentional implicit type conversion.), then I'll do the implicit test.
 
V

Victor Bazarov

Andre said:
Personal style: ick. I prefer to explicitly test against 0 when
dealing with ints (I also prefer to explicitly mention NULL when
dealing with pointers too.) If the expression type is bool (or 99.9%
of the time intended to be treated as a bool, such as the void*
return of streams. It's not really intended to be used as a pointer,
but it prevents other unintentional implicit type conversion.), then
I'll do the implicit test.

Yes, as a matter of style I like seeing ints tested explicitly against
zero, but for pointers I like saying 'if (pointer) '. The syntax is
also very convenient for streams (both C and C++), where you don't care
for the variable to survive beyond the point of check.

Compare

if (FILE* blah = fopen("somename", "rb")) {
// do something with 'blah'
}

and

{
FILE* blah = fopen("somename", "rb");
if (blah != NULL) {
// do something with 'blah'
}
}

Did you notice the extra pair of braces? Ick! Besides, the former
code reads better, IMNSHO. "If file opens, do something", compared
to "open blah. if blah is not NULL ..." [..Wait a minute? Why am I
checking for NULL when the term should be "opens"? so now I need to
introduce an extra utility function or macro:

inline bool opened_OK(FILE* f) { return f != NULL; }

and write

{
FILE* blah = fopen("somename", "rb");
if (opened_OK(blah)) {
// do something with 'blah'
}
}

Ick!]

See my point?

V
 
A

Andre Kostur

Andre said:
Personal style: ick. I prefer to explicitly test against 0 when
dealing with ints (I also prefer to explicitly mention NULL when
dealing with pointers too.) If the expression type is bool (or 99.9%
of the time intended to be treated as a bool, such as the void*
return of streams. It's not really intended to be used as a pointer,
but it prevents other unintentional implicit type conversion.), then
I'll do the implicit test.

Yes, as a matter of style I like seeing ints tested explicitly against
zero, but for pointers I like saying 'if (pointer) '. The syntax is
also very convenient for streams (both C and C++), where you don't care
for the variable to survive beyond the point of check.

Compare

if (FILE* blah = fopen("somename", "rb")) {
// do something with 'blah'
}

and

{
FILE* blah = fopen("somename", "rb");
if (blah != NULL) {
// do something with 'blah'
}
}

Did you notice the extra pair of braces? Ick! Besides, the former
code reads better, IMNSHO. "If file opens, do something", compared
to "open blah. if blah is not NULL ..." [..Wait a minute? Why am I
checking for NULL when the term should be "opens"? so now I need to
introduce an extra utility function or macro:

Yep... but hopefully your function is small enough that the FILE* has the
scope of the entire function anyway. (Or suffer with a FILE* that has a
larger scope than strictly necessary).
inline bool opened_OK(FILE* f) { return f != NULL; }

and write

{
FILE* blah = fopen("somename", "rb");
if (opened_OK(blah)) {
// do something with 'blah'
}
}

This would be the pain of using C-style functions :) Use streams :)
Ick!]

See my point?

Sure... the style doesn't work for you. Arguably if you need to add
additional braces, perhaps you should consider refactoring that piece of
code into its own function.
 
V

Victor Bazarov

Andre said:
Andre said:
@news.datemas.de:

Zachary Turner wrote:
Hello,

This seems like an extremely basic question, and I'm a bit
embarassed that I can't answer it myself.

I just recently started using GCC and tried to type the following
code:

while ((int i = getint()) != 0)

Drop the "!= 0" part and you'll have a standard construct.

Personal style: ick. I prefer to explicitly test against 0 when
dealing with ints (I also prefer to explicitly mention NULL when
dealing with pointers too.) If the expression type is bool (or
99.9% of the time intended to be treated as a bool, such as the
void* return of streams. It's not really intended to be used as a
pointer, but it prevents other unintentional implicit type
conversion.), then I'll do the implicit test.

Yes, as a matter of style I like seeing ints tested explicitly
against zero, but for pointers I like saying 'if (pointer) '. The
syntax is also very convenient for streams (both C and C++), where
you don't care for the variable to survive beyond the point of check.

Compare

if (FILE* blah = fopen("somename", "rb")) {
// do something with 'blah'
}

and

{
FILE* blah = fopen("somename", "rb");
if (blah != NULL) {
// do something with 'blah'
}
}

Did you notice the extra pair of braces? Ick! Besides, the former
code reads better, IMNSHO. "If file opens, do something", compared
to "open blah. if blah is not NULL ..." [..Wait a minute? Why am I
checking for NULL when the term should be "opens"? so now I need to
introduce an extra utility function or macro:

Yep... but hopefully your function is small enough that the FILE* has
the scope of the entire function anyway. (Or suffer with a FILE*
that has a larger scope than strictly necessary).

Why suffer?
This would be the pain of using C-style functions :) Use streams :)

Goes the same way

if (std::ifstream blah("somename", ios::binary)) {
// do something with blah
}

Works like a charm with any C++ objects that define operator void* or
operator bool to indicate "good state".
Ick!]

See my point?

Sure... the style doesn't work for you. Arguably if you need to add
additional braces, perhaps you should consider refactoring that piece
of code into its own function.

Nope. I have a perfectly working language construct that I use instead.

V
 
Z

Zachary Turner

Thanks for the response. It appears (to no real surprise to myself)
that I'm just getting crazy in my old age. I went back and tried my
compiler which I thought accepted this and it complains as well. I
know I've declared variables in while loop parentheses hundreds if not
thousands of times, I guess I never had it parenthesized like I
thought I did. Not sure what gave me the idea to try it all of a
sudden!

Zach
 
J

James Kanze

Yes. The second is readable, the first isn't.
Did you notice the extra pair of braces? Ick! Besides, the former
code reads better, IMNSHO. "If file opens, do something", compared
to "open blah. if blah is not NULL ..." [..Wait a minute? Why am I
checking for NULL when the term should be "opens"? so now I need to
introduce an extra utility function or macro:
Yep... but hopefully your function is small enough that the FILE* has
the scope of the entire function anyway. (Or suffer with a FILE*
that has a larger scope than strictly necessary).
Why suffer?

Why, quite? If the function is long enough for it to make a
difference, it's too long.
Goes the same way

if (std::ifstream blah("somename", ios::binary)) {
// do something with blah
}

Which is just as bad?

This is a major misfeature of C++; all it leads to is unreadable
code.
 
V

Victor Bazarov

James said:
[.. style differences identified ..]
This is a major misfeature of C++; all it leads to is unreadable
code.

Readability of the code is NOT an objective characteristic, we
should abandon this religious debate right here. Deal?

V
 
A

Andre Kostur

James said:
[.. style differences identified ..]
This is a major misfeature of C++; all it leads to is unreadable
code.

Readability of the code is NOT an objective characteristic, we
should abandon this religious debate right here. Deal?

Kinda why I stopped... this is all up to personal preference. I like my
way, you like yours, we're not hurting each other....
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,768
Messages
2,569,574
Members
45,051
Latest member
CarleyMcCr

Latest Threads

Top