测试。(C / CPP)
#include <stdio.h>
int main(int argc, char** argv)
{
int a = 0, b = 0;
printf("a = %d, b = %d\n", a, b);
b = (++a)--;
printf("a = %d, b = %d\n", a, b);
return 0;
}
如果我将上述内容保存为.cpp文件,它会在执行时编译并输出:
a = 0, b = 0
a = 0, b = 1
但是,如果我将其保存为.c文件,则会出现以下错误:
test.c:7:12: error: lvalue required as decrement operator.
在(++a)
操作之前,不应该解析(newValue)--
操作吗?有没有人对此有任何见解?
答案 0 :(得分:13)
在C中,前缀和后缀增量/减量运算符的结果不是左值。
在C ++中,后缀增量/减量运算符的结果也不是左值,但前缀增量/减量运算符的结果是左值。
现在在C ++中执行类似(++a)--
的操作是未定义的行为,因为您在两个序列点之间修改了两次对象值。
编辑:跟进@ bames53评论。它是C ++ 98 / C ++ 03中未定义的行为,但C ++ 11中关于序列点概念的变化现在定义了这个表达式。
答案 1 :(得分:3)
在C和C ++中,有左值表达式可以在=
运算符的左侧使用,右值表达式可以不使用。 C ++允许更多的东西成为左值,因为它支持引用语义。
++ a = 3; /* makes sense in C++ but not in C. */
递增和递减运算符类似于赋值,因为它们修改了它们的参数。
在C ++ 03中,(++a)--
会导致未定义的行为,因为两个相互之间没有排序的操作正在修改同一个变量。 (即使一个是“前”,一个是“发布”,但它们没有排序,因为没有,
,&&
,?
等。)
在C ++ 11中,表达式现在可以满足您的期望。但是C11并没有改变任何这样的规则,这是一个语法错误。
答案 2 :(得分:2)
对于任何可能需要准确的差异细节的人,如标准中所述,C99,§6.5.3/ 2说:
前缀++运算符的操作数的值递增。结果是新的 增量后操作数的值。
相比之下,C ++ 11,§5.3.2/ 1说:
结果是更新的操作数;它是左值,如果是,它是一个位字段 操作数是一个位域。
[重点补充,两种情况下]
另请注意,虽然(++a)--
在a
为int
时提供了未定义的行为(至少在C ++ 03中),但a
是某些用户定义的类型,所以你使用自己的++
和--
重载,将定义行为 - 在这种情况下,你得到相当于:
a.operator++().operator--(0);
由于每个运算符都会导致函数调用(不能重叠),实际上做有序列点来强制定义行为(请注意,我不建议使用它,只注意到行为实际上是在这种情况下定义的。)
答案 3 :(得分:0)
§5.2.7增量和减量:
post fi x
++
表达式的值是其操作数的值。 [...] 操作数应为可修改的左值。
C编译中出现的错误有助于表明这只是C ++中的一个功能。