我=(i,++ i,1)+ 1; 做?

gsa*_*ras 175 c expression operators compiler-warnings comma-operator

在阅读有关未定义行为和序列点的答案后,我写了一个小程序:

#include <stdio.h>

int main(void) {
  int i = 5;
  i = (i, ++i, 1) + 1;
  printf("%d\n", i);
  return 0;
}
Run Code Online (Sandbox Code Playgroud)

输出是2.天啊,我没有看到减量来了!这里发生了什么?

另外,在编译上面的代码时,我收到一条警告:

px.c:5:8:警告:逗号表达式的左侧操作数无效

  [-Wunused-value]   i = (i, ++i, 1) + 1;
                        ^
Run Code Online (Sandbox Code Playgroud)

为什么?但可能会通过我的第一个问题的答案自动回答.

hac*_*cks 257

在表达式中(i, ++i, 1),使用的逗号是逗号运算符

逗号运算符(由标记表示,)是一个二元运算符,它计算其第一个操作数并丢弃结果,然后计算第二个操作数并返回该值(和类型).

因为它丢弃了它的第一个操作数,所以它通常仅在第一个操作数具有所需副作用的情况下才有用.如果没有发生对第一个操作数的副作用,则编译器可能会生成有关表达式的警告而不起作用.

因此,在上面的表达式中,i将评估最左边的值,并且将丢弃其值.然后++i将被评估并将增加i1并且表达式的值++i将被丢弃,但副作用i是永久的.然后1将进行评估,表达式的值将是1.

它相当于

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;  
Run Code Online (Sandbox Code Playgroud)

请注意,上面的表达式是完全有效的,并且不会调用未定义的行为,因为在对逗号运算符的左右操作数的求之间存在一个序列点.

  • @Koushik; `i`用`5`初始化.查看声明语句`int i = 5;`. (2认同)

Sou*_*osh 62

引用C11,章节6.5.17,逗号运算符

逗号运算符的左操作数被计算为void表达式; 它的评估与右操作数之间存在一个序列点.然后评估右操作数; 结果有它的类型和价值.

所以,在你的情况下,

(i, ++i, 1)
Run Code Online (Sandbox Code Playgroud)

被评估为

  1. i,被评估为void表达式,值被丢弃
  2. ++i,被评估为void表达式,值被丢弃
  3. 最后,1返回值.

所以,最后的陈述看起来像

i = 1 + 1;
Run Code Online (Sandbox Code Playgroud)

i得到2.我想这可以解答你的两个问题,

  • 如何i获得价值2?
  • 为什么会有警告信息?

注意:FWIW,因为有一个顺序点的左手操作数的评价之后存在,就像表达式(i, ++i, 1)将不会调用UB,作为一个可能通常误认为.


dla*_*ask 30

i = (i, ++i, 1) + 1;
Run Code Online (Sandbox Code Playgroud)

让我们一步一步地分析它.

(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
Run Code Online (Sandbox Code Playgroud)

所以我们得到2.最后的任务现在:

i = 2;
Run Code Online (Sandbox Code Playgroud)

无论现在被覆盖之前是什么.


Gop*_*opi 19

结果

(i, ++i, 1)
Run Code Online (Sandbox Code Playgroud)

1
Run Code Online (Sandbox Code Playgroud)

对于

(i,++i,1) 
Run Code Online (Sandbox Code Playgroud)

评估发生时,,操作员丢弃评估值并保留最正确的值1

所以

i = 1 + 1 = 2
Run Code Online (Sandbox Code Playgroud)


Tom*_*han 14

你会在Comma运营商的维基页面上找到一些好的阅读材料.

基本上,它

...计算其第一个操作数并丢弃结果,然后计算第二个操作数并返回该值(和类型).

这意味着

(i, i++, 1)
Run Code Online (Sandbox Code Playgroud)

反过来,将评估i,丢弃结果,评估i++,丢弃结果,然后评估并返回1.


son*_*yao 13

你需要知道逗号运算符在这里做了什么:

你的表达:

(i, ++i, 1)
Run Code Online (Sandbox Code Playgroud)

计算第一个表达式,i计算第二个表达式++i,并1为整个表达式返回第三个表达式.

结果是:i = 1 + 1.

对于你的奖金问题,如你所见,第一个表达式i根本没有效果,所以编译器会抱怨.


Luc*_*ano 5

逗号具有"反向"优先权.这是您从IBM(70年代/ 80年代)的旧书和C手册中获得的内容.所以最后一个'命令'是父表达式中使用的.

在现代C中,它的使用很奇怪但在旧C(ANSI)中非常有趣:

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

虽然从左到右调用所有操作(函数),但只有最后一个表达式将用作条件'while'的结果.这样可以防止处理'goto'以在条件检查之前保持一个唯一的命令块.

编辑:这也避免了对处理函数的调用,该处理函数可以处理左操作数的所有逻辑,因此返回逻辑结果.请记住,我们在C的过去没有内联函数.因此,这可以避免调用开销.