comma in a c statement, ie for(i=0,i2=0;i<10;i++,i2)

T

Test

I have:

for (i=0,i2=0;i<10;i++,i2++)
{
.. some code
}

Is "," (comma) oke here?

I am converting below code to for -loop:

i=0;
i2=0;
while (i<10)
{
... some code
i++;
i2++;
}

Which is executed first in for (i=0,i2=0;i<10;i++,i2++)? i2=0 or i=0?

Any caveats? I could not find explanation to comma usage (maybe not not looking
hard enough).
 
B

Ben Bacarisse

Test said:
I have:

for (i=0,i2=0;i<10;i++,i2++)
{
.. some code
}

Is "," (comma) oke here?

Yes, though it's not obvious why you need both i and i2.. A few spaces
might be a good idea, though:

for (i = 0, i2 = 0; i < 10; i++, i2++)
I am converting below code to for -loop:

i=0;
i2=0;
while (i<10)
{
... some code
i++;
i2++;
}

How odd. What's the point of have both i and i2? If either gets
altered in the "some code" part then there is an argument for not
re-writing it as a "for" loop. Generally, readers will expect the
variables mentioned in a "for" loops to be left alone in the body. This
is not rule of the language but it's a good rule of thumb.

Note, also, that your "for" loop will not be the same as the "while"
loop if the while loop uses "continue".
Which is executed first in for (i=0,i2=0;i<10;i++,i2++)? i2=0 or i=0?

i = 0.
Any caveats? I could not find explanation to comma usage (maybe not
not looking hard enough).

It is often considered a little confusing since the comma token has lots
of uses in C.
 
M

Malcolm McLean

I have:

for (i=0,i2=0;i<10;i++,i2++)

{

.. some code

}


Is "," (comma) oke here?
Yes

Any caveats? I could not find explanation to comma usage
Comma operators are very seldom used because there's not much need for them.
An exception is in for loops, where you might want to have two loop counters
going at once. Even here, most C programmers prefer the style

for(i=0;i<N;i++)
{
units = 0;
tens[i*10] = 0;
}
 
J

James Kuyper

I have:

for (i=0,i2=0;i<10;i++,i2++)
{
.. some code
}

Is "," (comma) oke here?
Yes.

I am converting below code to for -loop:

i=0;
i2=0;
while (i<10)
{
... some code
i++;
i2++;
}

Which is executed first in for (i=0,i2=0;i<10;i++,i2++)? i2=0 or i=0?

The expression i=0 is executed first, though in this particular case it
doesn't matter.
Any caveats? I could not find explanation to comma usage (maybe not not looking
hard enough).

The expression E1,E2, where E1 is any expression, and E2 is any
expression other than another comma expression, causes expression E1 to
be evaluated. The result of that evaluation is discarded, so it only
make sense to do this if E1 is an expression with side effects, such as
a=3, b++, or printf("error:%g", d). After all side effects of E1 are
complete, expression E2 is evaluated. The value of expression E2 is also
the value of the comma expression as a whole. Thus "a = (b++,c)" is
equivalent to "b++; a=c;". It only makes sense to use a comma expression
when such a re-write is not possible, as in a for() statement such as
the one you ask about above.

A key point to understand is that commas are NOT always part of a comma
expression. The parameters of a function declaration and the arguments
of a function call are separated by commas, and the same is true for
function-like macros. Commas separate the initializers for the elements
of an array or members of a structure. A single declaration can declare
multiple declarators, separated by commas, as in "int a,b;". Commas are
used to separate the members of a union or enumeration. Commas are also
used in _Generic() expressions and _Static_assert() declarations, which
are new features of C2011, syntactically similar to function calls.

If you wish to use a comma expression in one of those contexts, you'll
have to parenthesize it, to prevent misinterpretation of the comma.
printf("hello %s", "world!\n") does something different from
printf( ("hello %s", "world!\n") ).
 
J

James Kuyper

I have:

for (i=0,i2=0;i<10;i++,i2++)
{
.. some code
}

Is "," (comma) oke here?
Yes.

I am converting below code to for -loop:

i=0;
i2=0;
while (i<10)
{
... some code
i++;
i2++;
}

Which is executed first in for (i=0,i2=0;i<10;i++,i2++)? i2=0 or i=0?

The expression i=0 is executed first, though in this particular case it
doesn't matter.
Any caveats? I could not find explanation to comma usage (maybe not not looking
hard enough).

The expression E1,E2, where E1 is any expression, and E2 is any
expression other than another comma expression, causes expression E1 to
be evaluated. The result of that evaluation is discarded, so it only
make sense to do this if E1 is an expression with side effects, such as
a=3, b++, or printf("error:%g", d). After all side effects of E1 are
complete, expression E2 is evaluated. The value of expression E2 is also
the value of the comma expression as a whole. Thus "a = (b++,c)" is
equivalent to "b++; a=c;". It only makes sense to use a comma expression
when such a re-write is not possible, as in a for() statement such as
the one you ask about above.

A key point to understand is that commas are NOT always part of a comma
expression. The parameters of a function declaration and the arguments
of a function call are separated by commas, and the same is true for
function-like macros. Commas separate the initializers for the elements
of an array or members of a structure. A single declaration can declare
multiple declarators, separated by commas, as in "int a,b;". Commas are
used to separate the members of a union or enumeration. Commas are also
used in _Generic() expressions and _Static_assert() declarations, which
are new features of C2011, syntactically similar to function calls.

If you wish to use a comma expression in one of those contexts, you'll
have to parenthesize it, to prevent misinterpretation of the comma.
printf("hello %s", "world!\n") does something different from
printf( ("hello %s", "world!\n") ).
 
L

Les Cargill

Malcolm said:
I have:

for (i=0,i2=0;i<10;i++,i2++)

{

.. some code

}


Is "," (comma) oke here?
Yes

Any caveats? I could not find explanation to comma usage
Comma operators are very seldom used because there's not much need for them.
An exception is in for loops, where you might want to have two loop counters
going at once. Even here, most C programmers prefer the style

for(i=0;i<N;i++)
{
units = 0;
tens[i*10] = 0;
}


I also like:
for(i=0;i<N;i++)
{
const int i2 = (i*10);
units = 0;
tens[i2] = 0;
}

which seems silly for that simple of a loop, but
has come in handy ( especially when i2 is assigned
from a function return )
 
K

Keith Thompson

James Kuyper said:
A key point to understand is that commas are NOT always part of a comma
expression. The parameters of a function declaration and the arguments
of a function call are separated by commas, and the same is true for
function-like macros. Commas separate the initializers for the elements
of an array or members of a structure. A single declaration can declare
multiple declarators, separated by commas, as in "int a,b;". Commas are
used to separate the members of a union or enumeration.

How do commas separate the members of a union?
Commas are also
used in _Generic() expressions and _Static_assert() declarations, which
are new features of C2011, syntactically similar to function calls.
[...]
 
G

glen herrmannsfeldt

(snip)
How odd. What's the point of have both i and i2? If either gets
altered in the "some code" part then there is an argument for not
re-writing it as a "for" loop. Generally, readers will expect the
variables mentioned in a "for" loops to be left alone in the body. This
is not rule of the language but it's a good rule of thumb.

I have used "for" loops where I needed "continue" to restart
the loop without incrementing the index.

Otherwise, I agree.

-- glen
 
B

Ben Bacarisse

glen herrmannsfeldt said:
(snip)


I have used "for" loops where I needed "continue" to restart
the loop without incrementing the index.

Otherwise, I agree.

So when you want that behaviour you'd write:

for (<initialise>; <condition>;) {
<code that uses continue>
<increment>
}

rather than

<initialise>
while (<condition>) {
<code that uses continue>
<increment>
}

? I don't think I would (and I could make hand-waving arguments about
why I wouldn't) but it's really just a matter to taste.
 
L

Les Cargill

Ben said:
So when you want that behaviour you'd write:

for (<initialise>; <condition>;) {
<code that uses continue>
<increment>
}

rather than

<initialise>
while (<condition>) {
<code that uses continue>
<increment>
}

? I don't think I would (and I could make hand-waving arguments about
why I wouldn't) but it's really just a matter to taste.


As soon as you need a break or continue in the for loop, my
heuristic is to go with a while. But I'm not always consistent
about it...
 
S

Shao Miller

So when you want that behaviour you'd write:

for (<initialise>; <condition>;) {
<code that uses continue>
<increment>
}

rather than

<initialise>
while (<condition>) {
<code that uses continue>
<increment>
}

? I don't think I would (and I could make hand-waving arguments about
why I wouldn't) but it's really just a matter to taste.

It can also be a matter of lifetime (for C >= C99), which could
potentially impact memory usage. By using declarations (but not
compound literals) in the 'for', such objects needn't've storage for the
enclosing block.

- Shao Miller
 
J

James Kuyper

How do commas separate the members of a union?

They don't - that comment started life as a very different statement
about structs, unions, and enumerations, and I forgot to remove the part
about unions when I did a major re-write of the statement that rendered
it no longer applicable to unions. Sorry for the confusion (I don't
expect that you were confused, but the OP might have been).
 
G

glen herrmannsfeldt

(snip on the comma operator used in for loops, then I wrote)
So when you want that behaviour you'd write:
for (<initialise>; <condition>;) {
<code that uses continue>
<increment>
}
rather than
<initialise>
while (<condition>) {
<code that uses continue>
<increment>
}

It might have started out as a normal "for" loop before I realized
that the "continue" was needed, but yes. As long as the initialization
was related to the loop, I would probably use for.

I tend to use "while" where the condition is a function call, not
a test on a loop variable, such as with fgets().
? I don't think I would (and I could make hand-waving arguments about
why I wouldn't) but it's really just a matter to taste.

-- glen
 
B

Ben Bacarisse

Shao Miller said:
It can also be a matter of lifetime (for C >= C99), which could
potentially impact memory usage. By using declarations (but not
compound literals) in the 'for', such objects needn't've storage for
the enclosing block.

That does not match my understanding. Can you provide supporting
evidence?

Putting a declaration in a for statement (as opposed to just before a
while) alters the scope the scope of the name but does not, I think,
have any effect on the lifetime of the declared object.
 
S

Shao Miller

That does not match my understanding. Can you provide supporting
evidence?

Putting a declaration in a for statement (as opposed to just before a
while) alters the scope the scope of the name but does not, I think,
have any effect on the lifetime of the declared object.

Sure thing. C99 6.8.5.3p1 with 6.2.4p6.

Personally, these days I like to declare everything at the top of a
function, so I don't actually take advantage of this, but it might be
worth noting, for C >= C99.

- Shao Miller
 
K

Keith Thompson

Shao Miller said:
Sure thing. C99 6.8.5.3p1 with 6.2.4p6.

Personally, these days I like to declare everything at the top of a
function, so I don't actually take advantage of this, but it might be
worth noting, for C >= C99.

6.8.5.3p1:
If *clause-1* is a declaration, the scope of any identifiers
it declares is the remainder of the declaration and the entire
loop, including the other two expressions

6.2.4p6:
For such an object that does not have a variable length array type,
its lifetime extends from entry into the block with which it is
associated until execution of that block ends in any way.

So my interpretation of that is:

void foo(void) { /* lifetime of i starts here */
this();
that();
for (int i = 0 /* scope of i starts here */; i < 100; i ++) {
the_other_thing(i);
/* scope of i ends here */
}
yet_another_thing();
/* lifetime of i ends here */
}

The "block with which it is associated" is the outer block for the
function, not the block that is the statement controlled by the for
loop.

Remember that the statement controlled by a for loop needn't be a block:

for (int i = 0; i < 100; i ++)
single_statement();

If `i` were defined just above the for loop, the lifetime and scope would
be the same as they are in my example.
 
B

Ben Bacarisse

Shao Miller said:
Sure thing. C99 6.8.5.3p1 with 6.2.4p6.

These support exactly what I said. I don't see any support there for
the change in the lifetime that you suggested.
 
S

Shao Miller

6.8.5.3p1:
If *clause-1* is a declaration, the scope of any identifiers
it declares is the remainder of the declaration and the entire
loop, including the other two expressions

6.2.4p6:
For such an object that does not have a variable length array type,
its lifetime extends from entry into the block with which it is
associated until execution of that block ends in any way.

I must _sincerely_ apologize. This must be a circumstance where
N1256.PDF differs from C99. Please forgive me for referring to the
wrong point! N1256.PDF's 6.2.4p6:

"For such an object that does have a variable length array type, its
lifetime extends from the declaration of the object until execution of
the program leaves the scope of the declaration.27) If the scope is
entered recursively, a new instance of the object is created each time.
The initial value of the object is indeterminate."
So my interpretation of that is:

void foo(void) { /* lifetime of i starts here */
this();
that();
for (int i = 0 /* scope of i starts here */; i < 100; i ++) {
the_other_thing(i);
/* scope of i ends here */
}
yet_another_thing();
/* lifetime of i ends here */
}

The "block with which it is associated" is the outer block for the
function, not the block that is the statement controlled by the for
loop.

Remember that the statement controlled by a for loop needn't be a block:

for (int i = 0; i < 100; i ++)
single_statement();

If `i` were defined just above the for loop, the lifetime and scope would
be the same as they are in my example.


Because VLAs are the predominant feature for C99 from my perspective, I
realize now that I've actually skipped mentioning them, but they are
precisely what I'm referring to.

- Shao Miller
 
S

Shao Miller

These support exactly what I said. I don't see any support there for
the change in the lifetime that you suggested.

With _much_ apology, I've assumed that N1256.PDF's 6.2.4p6 is C99's. I
am referring to C99's VLAs, which obviously introduce a number of quirks
(relative to C89/C90). One of those quirks is that their lifetime and
scope are fairly closely tied, and it's relevant for a 'for' loop's
clause-1. (_Why_ one would declare a VLA in a 'for' loop is a matter of
practicality, but _that_ one can is a matter of fact.)

Or, I could be missing something.

- Shao Miller
 

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

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,007
Latest member
obedient dusk

Latest Threads

Top