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

Discussion in 'C Programming' started by Test, Dec 15, 2012.

  1. Test

    Test Guest

    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).
     
    Test, Dec 15, 2012
    #1
    1. Advertisements

  2. 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++)
    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".
    i = 0.
    It is often considered a little confusing since the comma token has lots
    of uses in C.
     
    Ben Bacarisse, Dec 15, 2012
    #2
    1. Advertisements

  3. 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;
    }
     
    Malcolm McLean, Dec 15, 2012
    #3
  4. Test

    James Kuyper Guest

    The expression i=0 is executed first, though in this particular case it
    doesn't matter.
    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") ).
     
    James Kuyper, Dec 15, 2012
    #4
  5. Test

    James Kuyper Guest

    The expression i=0 is executed first, though in this particular case it
    doesn't matter.
    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") ).
     
    James Kuyper, Dec 15, 2012
    #5
  6. Test

    Les Cargill Guest



    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 )
     
    Les Cargill, Dec 15, 2012
    #6
  7. How do commas separate the members of a union?
    [...]
     
    Keith Thompson, Dec 15, 2012
    #7
  8. (snip)
    I have used "for" loops where I needed "continue" to restart
    the loop without incrementing the index.

    Otherwise, I agree.

    -- glen
     
    glen herrmannsfeldt, Dec 15, 2012
    #8
  9. 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.
     
    Ben Bacarisse, Dec 15, 2012
    #9
  10. Test

    Les Cargill Guest


    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...
     
    Les Cargill, Dec 15, 2012
    #10
  11. Test

    Shao Miller Guest

    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
     
    Shao Miller, Dec 15, 2012
    #11
  12. Test

    James Kuyper Guest

    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).
     
    James Kuyper, Dec 15, 2012
    #12
  13. (snip on the comma operator used in for loops, then I wrote)
    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().
    -- glen
     
    glen herrmannsfeldt, Dec 15, 2012
    #13
  14. 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.
     
    Ben Bacarisse, Dec 15, 2012
    #14
  15. Test

    Shao Miller Guest

    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
     
    Shao Miller, Dec 15, 2012
    #15
  16. 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.
     
    Keith Thompson, Dec 15, 2012
    #16
  17. These support exactly what I said. I don't see any support there for
    the change in the lifetime that you suggested.
     
    Ben Bacarisse, Dec 16, 2012
    #17
  18. Test

    Shao Miller Guest

    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."


    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
     
    Shao Miller, Dec 16, 2012
    #18
  19. Test

    Shao Miller Guest

    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
     
    Shao Miller, Dec 16, 2012
    #19
  20. Test

    Philip Lantz Guest

    union u {
    int x, y;
    };

    :)
     
    Philip Lantz, Dec 16, 2012
    #20
    1. Advertisements

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 (here). After that, you can post your question and our members will help you out.