8

测试。(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)--手术吗?有人对此有任何见解吗?

4

4 回答 4

14

在 C 中,前缀和后缀递增/递减运算符的结果不是左值。

在 C++ 中,后缀递增/递减运算符的结果也不是左值,但前缀递增/递减运算符的结果是左值。

现在在 C++ 中做类似的事情(++a)--是未定义的行为,因为您在两个序列点之间修改了两次对象值。

编辑:跟进@bames53 评论。它在 C++98/C++03 中是未定义的行为,但 C++11 中关于序列点概念的更改现在使该表达式已定义。

于 2013-02-10T14:55:15.163 回答
3

在 C 和 C++ 中,左值表达式可以用在运算符的左侧,=而右值表达式则不能。C++ 允许更多的东西成为左值,因为它支持引用语义。

++ a = 3; /* makes sense in C++ but not in C. */

递增和递减运算符类似于赋值,因为它们修改了它们的参数。

在 C++03 中,(++a)--会导致未定义的行为,因为两个没有相互排序的操作正在修改同一个变量。(即使一个是“pre”,一个是“post”,它们是无序的,因为没有,, &&,?等。)

在 C++11 中,表达式现在可以满足您的期望。但是 C11 并没有改变任何这样的规则,这是一个语法错误。

于 2013-02-10T14:58:09.393 回答
2

对于任何可能想要标准中所述差异的精确细节的人,C99,§6.5.3/2 说:

前缀 ++ 运算符的操作数的值递增。结果是递增后操作数的新

相比之下,C++11,§5.3.2/1 说:

结果是更新的操作数;它是一个左值,如果操作数是一个位域,它就是一个位域。

[强调,在这两种情况下]

另请注意,虽然在is an(++a)--时给出了未定义的行为(至少在 C++03 中),但 if是一些用户定义的类型,所以您使用自己的and重载,行为将被定义——在这种情况下,你得到相当于:ainta++--

a.operator++().operator--(0);

由于每个运算符都会导致一个函数调用(不能重叠),因此您实际上确实有序列点来强制定义行为(请注意,我不建议使用它,只注意在这种情况下实际定义了行为)。

于 2013-02-10T15:04:34.787 回答
0

§5.2.7 递增和递减:

后缀++表达式的值是其操作数的值。[...]  操作数应该是一个可修改的左值

您在 C 编译中遇到的错误有助于表明这只是 C++ 中存在的一个功能。

于 2013-02-10T15:02:58.143 回答