Discussion:
c99 style for() and multiple variables
(too old to reply)
Kenny McCormack
2017-03-29 10:23:09 UTC
Permalink
Raw Message
We know that if you are using c99 or later, then you can replace:

int i;
...

for (i = 0; ...)

with:
for (int i = 0; ...)

So far, so good. But what if you have more than one control variable in
the for() loop? Well, experimentation shows that you can, in fact, do:

for (int i = 0, j = 97; ...)

(As long as i and j are both ints)

But what if you need to do the equivalent of:

int i;
double d;
...

for (i = 0, d = 3.14159; ...)

Can this be done?

Or, even more bizarre, how about?

double d;
...

for (int i = 0, d = 3.14159; ...)

Here, we want i to be local to the loop, but d to be the one declared at
the top of the block.
--
The randomly chosen signature file that would have appeared here is more than 4
lines long. As such, it violates one or more Usenet RFCs. In order to remain
in compliance with said RFCs, the actual sig can be found at the following URL:
http://user.xmission.com/~gazelle/Sigs/CLCtopics
bartc
2017-03-29 11:38:17 UTC
Permalink
Raw Message
Post by Kenny McCormack
int i;
...
for (i = 0; ...)
for (int i = 0; ...)
So far, so good. But what if you have more than one control variable in
for (int i = 0, j = 97; ...)
(As long as i and j are both ints)
int i;
double d;
...
for (i = 0, d = 3.14159; ...)
Can this be done?
The above is fine, you're just assigning to those previously declared
variables.
Post by Kenny McCormack
Or, even more bizarre, how about?
double d;
...
for (int i = 0, d = 3.14159; ...)
Here, we want i to be local to the loop, but d to be the one declared at
the top of the block.
No, you're declaring two new ints, i and d. d will be initialised to 3.
You'd have to initialise d, as a double, outside the loop. And not
shadow it with a new declaration of d.
--
bartc

---
This email has been checked for viruses by Avast antivirus software.
https://www.avast.com/antivirus
Andrey Tarasevich
2017-03-29 20:06:35 UTC
Permalink
Raw Message
Post by Kenny McCormack
Or, even more bizarre, how about?
double d;
...
for (int i = 0, d = 3.14159; ...)
Here, we want i to be local to the loop, but d to be the one declared at
the top of the block.
This is actually possible

double d;
...

for (int i = (d = 3.14159, 0); ...)

Readability of such code goes all the way up to 11.

But declaring variables of different types in 'for' statement is not
supported.
--
Best regards,
Andrey Tarasevich
Kenny McCormack
2017-03-29 21:01:05 UTC
Permalink
Raw Message
In article <obh3ur$17f$***@dont-email.me>,
Andrey Tarasevich <***@hotmail.com> wrote:
...
Post by Andrey Tarasevich
This is actually possible
double d;
...
for (int i = (d = 3.14159, 0); ...)
Cool. Thanks.
Post by Andrey Tarasevich
Readability of such code goes all the way up to 11.
Well, there is that.
Post by Andrey Tarasevich
But declaring variables of different types in 'for' statement is not
supported.
Yeah, that's basically the conclusion I was reaching.
Thanks for confirming it for me.
--
The randomly chosen signature file that would have appeared here is more than 4
lines long. As such, it violates one or more Usenet RFCs. In order to remain
in compliance with said RFCs, the actual sig can be found at the following URL:
http://user.xmission.com/~gazelle/Sigs/FreeCollege
James R. Kuyper
2017-03-29 21:59:43 UTC
Permalink
Raw Message
Post by Andrey Tarasevich
Post by Kenny McCormack
Or, even more bizarre, how about?
double d;
...
for (int i = 0, d = 3.14159; ...)
Here, we want i to be local to the loop, but d to be the one declared at
the top of the block.
This is actually possible
double d;
...
for (int i = (d = 3.14159, 0); ...)
Readability of such code goes all the way up to 11.
But declaring variables of different types in 'for' statement is not
supported.
The relevant grammar rules are 6.8.5p1:

for ( declaration expressionopt ; expressionopt ) statement

and 6.7p1:
declaration:
declaration-specifiers init-declarator-listopt ;

A key point is that multiple declarators are allowed in an
init-declarator-list. All the declarators must share the same
declaration-specifiers, which means that "int" and "double" cannot both
apply, the issue Kenny was worried about.

The declarators must declare objects, and the only storage class
specifiers allowed are "auto" and "register" (6.8.5p3). Therefore, the
inline and _Noreturn specifiers are also not allowed (6.7.4p1). If one
of the qualifiers is _Atomic, arrays are ruled out (6.7.3p3). However,
with those exceptions, each of the declarators could declare either a
single object, an array, or a pointer to an object, function, or array
(6.7.6p1).

Therefore, the declarators needn't all have the same type:

for(int i=0, array[3][2]={{0, 1}, {1, 2}, {2, 4}}, *pi = &i,
(*pfunc)(int)=func, (*parray)[2]=array+1; i < MAX; i++)
Andrey Tarasevich
2017-03-29 23:16:59 UTC
Permalink
Raw Message
Post by James R. Kuyper
Post by Andrey Tarasevich
But declaring variables of different types in 'for' statement is not
supported.
A key point is that multiple declarators are allowed in an
init-declarator-list. All the declarators must share the same
declaration-specifiers, which means that "int" and "double" cannot both
apply, the issue Kenny was worried about.
... which corrects my previous incorrect statement quoted above. It is
actually possible to declare variables of different types in the 'for'
loop header, as long as they all share the same *declaration-specifiers*
sequence, i.e. as long as all declarators reside in a single declaration.

E.g. declaring an 'int', an 'int[42]' and and 'int *' simultaneously in
a 'for' loop header is perfectly possible, even though these variables
have different types.
--
Best regards,
Andrey Tarasevich
Stefan Ram
2017-03-29 23:58:01 UTC
Permalink
Raw Message
Post by Andrey Tarasevich
E.g. declaring an 'int', an 'int[42]' and and 'int *' simultaneously in
a 'for' loop header is perfectly possible, even though these variables
have different types.
What seems to be compiled here:

#include <stdio.h>

int main( void )
{ for( struct{ int n; double x; }i ={ 2, 3.2 }; 0; ); }

.
Kenny McCormack
2017-03-30 12:49:39 UTC
Permalink
Raw Message
Post by Stefan Ram
Post by Andrey Tarasevich
E.g. declaring an 'int', an 'int[42]' and and 'int *' simultaneously in
a 'for' loop header is perfectly possible, even though these variables
have different types.
#include <stdio.h>
int main( void )
{ for( struct{ int n; double x; }i ={ 2, 3.2 }; 0; ); }
It doesn't seem to work. I changed your program slightly, to:

--- Cut Here ---
#include <stdio.h>

int main( void )
{
for (struct { int n; double x; } i = { 2, 3.2 }; i.n < 5; i.n++, i.x++)
printf("i.n = %d, i.x = %g\n",i.n,i.x);
}
--- Cut Here ---

clang on OSX (as "gcc"), says:

$ gcc x.c
x.c:5:10: error: declaration of non-local variable in 'for' loop
for (struct { int n; double x; } i = { 2, 3.2 }; i.n < 5; i.n++, i.x++)
^
1 error generated.
$
--
If the automobile had followed the same development cycle as the
computer, a Rolls-Royce today would cost $100, get a million miles to
the gallon, and explode once every few weeks, killing everyone inside.
Philip Lantz
2017-04-03 06:43:01 UTC
Permalink
Raw Message
Post by Stefan Ram
#include <stdio.h>
int main( void )
{ for( struct{ int n; double x; }i ={ 2, 3.2 }; 0; ); }
As Kenny demonstrated, this is not legal. It violates the constraint in
6.8.5p3: "The declaration part of a for statement shall only declare
identifiers for objects having storage class auto or register", in that
it declares two identifiers that are not identifiers for objects.
Keith Thompson
2017-04-03 16:23:11 UTC
Permalink
Raw Message
Post by Philip Lantz
Post by Stefan Ram
#include <stdio.h>
int main( void )
{ for( struct{ int n; double x; }i ={ 2, 3.2 }; 0; ); }
As Kenny demonstrated, this is not legal. It violates the constraint in
6.8.5p3: "The declaration part of a for statement shall only declare
identifiers for objects having storage class auto or register", in that
it declares two identifiers that are not identifiers for objects.
Interesting. gcc doesn't complain about this with "-std=c11 -pedantic",
but clang does:

error: declaration of non-local variable in 'for' loop
--
Keith Thompson (The_Other_Keith) kst-***@mib.org <http://www.ghoti.net/~kst>
Working, but not speaking, for JetHead Development, Inc.
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
Kenny McCormack
2017-04-04 01:56:42 UTC
Permalink
Raw Message
Post by Keith Thompson
Post by Philip Lantz
Post by Stefan Ram
#include <stdio.h>
int main( void )
{ for( struct{ int n; double x; }i ={ 2, 3.2 }; 0; ); }
As Kenny demonstrated, this is not legal. It violates the constraint in
6.8.5p3: "The declaration part of a for statement shall only declare
identifiers for objects having storage class auto or register", in that
it declares two identifiers that are not identifiers for objects.
Interesting. gcc doesn't complain about this with "-std=c11 -pedantic",
In fact, it even compiles with gcc and "-pedantic -std=c99".
Note that you need at least -std=c99 in order for for loop initializers to
work at all (with gcc).
--
Modern Conservative: Someone who can take time out from demanding more
flag burning laws, more abortion laws, more drug laws, more obscenity
laws, and more police authority to make warrantless arrests to remind
us that we need to "get the government off our backs".
Tim Rentsch
2017-04-17 02:43:15 UTC
Permalink
Raw Message
Post by Stefan Ram
#include <stdio.h>
int main( void )
{ for( struct{ int n; double x; }i ={ 2, 3.2 }; 0; ); }
As Kenny demonstrated, this is not legal. It violates the constraint in
6.8.5p3: "The declaration part of a for statement shall only declare
identifiers for objects having storage class auto or register", in that
it declares two identifiers that are not identifiers for objects.
I suspect this interpretation is misreading the intended meaning
of the passage (and apparently clang is also guilty of that).
Consider:

double d;
for( d = (union {uint64_t u; double d;}){ 0 }.d; d < 1.; d+=0.1 ){
/* certainly legal */
}

for( double d = (union {uint64_t u; double d;}){ 0 }.d; d < 1.; d+=0.1 ){
/* illegal??? */
}

The first for() statement is certainly legal.

The second for() statement has a declaration part that declares
identifiers for members of a tagless union type. Was it intended
that this second for() statement be a constraint violation just
because the 'd' variable was introduced by a local declaration?
That seems unlikely. (In case it needs pointing out, in C the
non-terminal 'declaration' also includes any initializers.)

Surely the meaning intended by this sentence in 6.8.5p3 is only
that the /principal/ declared identifiers be for objects of
storage class auto or register (ie, and not for functions, and
not of other storage classes). Other declared identifiers, such
as might occur in the type specifier, or in another part of a
declarator, or in an initializer, are not meant to be at issue.

Anyone up for filing a defect report?

Loading...