What does i = (i, ++i, 1) + 1; do?

♀尐吖头ヾ 提交于 2019-11-26 05:55:49

问题


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.


回答1:


In the expression (i, ++i, 1), the comma used is the comma operator

the comma operator (represented by the token ,) is a binary operator that evaluates its first operand and discards the result, and then evaluates the second operand and returns this value (and type).

Because 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 increment i by 1 and again the value of the expression ++i will be discarded, but the side effect to i is permanent. Then 1 will be evaluated and the value of the expression will be 1.

It is equivalent to

i;          // Evaluate i and discard its value. This has no effect.
++i;        // Evaluate i and increment it by 1 and discard the value of expression ++i
i = 1 + 1;  

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.




回答2:


Quoting from C11, chapter 6.5.17, Comma operator

The left operand of a comma operator is evaluated as a void expression; there is a sequence point between its evaluation and that of the right operand. Then the right operand is evaluated; the result has its type and value.

So, in your case,

(i, ++i, 1)

is evaluated as

  1. i, gets evaluated as a void expression, value discarded
  2. ++i, gets evaluated as a void expression, value discarded
  3. finally, 1, value returned.

So, the final statement looks like

i = 1 + 1;

and i gets to 2. I guess this answers both of your questions,

  • How i gets a value 2?
  • Why there is a warning message?

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.




回答3:


i = (i, ++i, 1) + 1;

Let's analyse it step by step.

(i,   // is evaluated but ignored, there are other expressions after comma
++i,  // i is updated but the resulting value is ignored too
1)    // this value is finally used
+ 1   // 1 is added to the previous value 1

So we obtain 2. And the final assignment now:

i = 2;

Whatever was in i before it's overwritten now.




回答4:


The outcome of

(i, ++i, 1)

is

1

For

(i,++i,1) 

the evaluation happens such that the , operator discards the evaluated value and will retain just the right most value which is 1

So

i = 1 + 1 = 2



回答5:


You'll find some good reading on the wiki page for the Comma operator.

Basically, it

... evaluates its first operand and discards the result, and then evaluates the second operand and returns this value (and type).

This means that

(i, i++, 1)

will, in turn, evaluate i, discard the result, evaluate i++, discard the result, and then evaluate and return 1.




回答6:


You need to know what the comma operator is doing here:

Your expression:

(i, ++i, 1)

The first expression, i, is evaluated, the second expression, ++i, is evaluated, and the third expression, 1, is returned for the whole expression.

So the result is: i = 1 + 1.

For your bonus question, as you see, the first expression i has no effect at all, so the compiler complains.




回答7:


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):

do { 
    /* bla bla bla, consider conditional flow with several continue's */
} while ( prepAnything(), doSomethingElse(), logic_operation);

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.



来源:https://stackoverflow.com/questions/30614396/what-does-i-i-i-1-1-do

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!