After reading this answer about undefined behavior and sequence points, I wrote a small program:
#include <stdio.h>
int main(void) {
int i = 5;
i = (i, ++i, 1) + 1;
printf("%d\n", i);
return 0;
}
The output is 2
. Oh God, I didn't see the decrement coming! What is happening here?
Also, while compiling the above code, I got a warning saying:
px.c:5:8: warning: left-hand operand of comma expression has no effect
[-Wunused-value] i = (i, ++i, 1) + 1; ^
Why? But probably it will be automatically answered by the answer of my first question.
You'll find some good reading on the wiki page for the Comma operator.
Basically, it
This means that
will, in turn, evaluate
i
, discard the result, evaluatei++
, discard the result, and then evaluate and return1
.Let's analyse it step by step.
So we obtain 2. And the final assignment now:
Whatever was in i before it's overwritten now.
The outcome of
is
For
the evaluation happens such that the
,
operator discards the evaluated value and will retain just the right most value which is1
So
In the expression
(i, ++i, 1)
, the comma used is the comma operatorBecause it discards its first operand, it is generally only useful where the first operand has desirable side effects. If the side effect to the first operand does not takes place, then the compiler may generate warning about the expression with no effect.
So, in the above expression, the leftmost
i
will be evaluated and its value will be discarded. Then++i
will be evaluated and will incrementi
by 1 and again the value of the expression++i
will be discarded, but the side effect toi
is permanent. Then1
will be evaluated and the value of the expression will be1
.It is equivalent to
Note that the above expression is perfectly valid and does not invoke undefined behavior because there is a sequence point between the evaluation of the left and right operands of the comma operator.
Quoting from
C11
, chapter6.5.17
, Comma operatorSo, in your case,
is evaluated as
i
, gets evaluated as a void expression, value discarded++i
, gets evaluated as a void expression, value discarded1
, value returned.So, the final statement looks like
and
i
gets to2
. I guess this answers both of your questions,i
gets a value 2?Note: FWIW, as there is a sequence point present after the evaluation of the left hand operand, an expression like
(i, ++i, 1)
won't invoke UB, as one may generally think by mistake.Comma has an 'inverse' precedence. This is what you will get from old books and C manuals from IBM (70s/80s). So the last 'command' is what is used in parent expression.
In modern C its use is strange but is very interesting in old C (ANSI):
While all operations (functions) are called from left to right, only the last expression will be used as a result to conditional 'while'. This prevent handling of 'goto's to keep a unique block of commands to run before condition check.
EDIT: This avoid also a call to a handling function which could take care of all logic at left operands and so return the logical result. Remember that, we had not inline function in the past of C. So, this could avoid a call overhead.