Turn Turn - 2 months ago 11
C Question

Why is gcc not treating comma as a sequence point?

I'm observing different behavior regarding what I think is part of the C standard between

clang
and
gcc
(either the homebrew version on my mac or on linux). The question is whether the comma in an argument list is a sequence point or not.
clang
interprets it as such but
gcc
does not.

This code demonstrates the issue:

#include <stdio.h>

int inner(int *v) {
*v += 1;
return 1;
}

int outer(int x, int y) {
return y;
}

int main(int argc, char *argv[]) {
int x = 4;
printf ("result=%d\n", outer(inner(&x), x));
}


And the results:

$ clang -o comseq comseq.c && ./comseq
result=5
$ gcc-4.8 -o comseq comseq.c && ./comseq
result=4
$ gcc-5 -o comseq comseq.c && ./comseq
result=4


I don't have access to a copy of the C standard at the moment, but I was pretty sure that
clang
's behavior was correct until I saw
gcc
's interpretation. Playing with the
--std=
option didn't change my results at all.

ETA

On a better reading it is true that this question is answered in http://stackoverflow.com/a/4176333/3171657:


a , b (§5.18) (in func(a,a++) , is not a comma operator, it's merely a separator between the arguments a and a++. The behaviour is undefined in that case if a is considered to be a primitive type)


but that, while very useful, is a long answer so maybe leaving this question around will help other users like myself. Also, to be pedantic, that question is about C++, not C.

Answer

Commas in argument lists are not sequence points — they are not comma operators within the meaning of the term.

The section of the standard (ISO/IEC 9899:2011) on function calls (§6.5.2.2) says:

¶3 A postfix expression followed by parentheses () containing a possibly empty, comma- separated list of expressions is a function call. The postfix expression denotes the called function. The list of expressions specifies the arguments to the function.

¶4 An argument may be an expression of any complete object type. In preparing for the call to a function, the arguments are evaluated, and each parameter is assigned the value of the corresponding argument.

¶10 There is a sequence point after the evaluations of the function designator and the actual arguments but before the actual call. Every evaluation in the calling function (including other function calls) that is not otherwise specifically sequenced before or after the execution of the body of the called function is indeterminately sequenced with respect to the execution of the called function.

(I've omitted a couple of footnotes, but the contents are not germane to the discussion.)

There is nothing about the expressions being evaluated in any particular sequence.

Note, too, that a comma operator yields a single value. If you interpreted:

function(x, y)

as having a comma operator, the function would have only one argument — the value of y. This isn't the way functions work, of course. If you want a comma operator there, you have to use extra parentheses:

function((x, y))

Now function() is called with a single value, which it the value of y, but that is evaluated after x is evaluated. Such notation is seldom used, not least because it is likely to confuse people.

Comments