为什么多个增量/递减在C++中有效,而在C中无效
Why are multiple increments/decrements valid in C++ but not in C?
测试。(c/cpp)
#include <stdio.h>
int main(int argc, char** argv)
{
int a = 0, b = 0;
printf("a = %d, b = %dn", a, b);
b = (++a)--;
printf("a = %d, b = %dn", 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)--
操作之前解决吗?有人对此有什么见解吗?
在C中,前缀和后缀递增/递减运算符的结果不是左值。
在C++中,后缀递增/递减运算符的结果也不是左值,但前缀递增/递减操作符的结果是左值。
现在,在C++中执行类似(++a)--
的操作是未定义的行为,因为您要在两个序列点之间修改对象值两次。
编辑:关注@bames53评论。它在C++98/C++03中是未定义的行为,但C++11中对序列点思想的改变现在使这个表达式得到了定义。
在C和C++中,有一些左值表达式可以在=
运算符的左侧使用,也有一些右值表达式可以不使用。C++允许更多的东西成为lvalue,因为它支持引用语义。
++ a = 3; /* makes sense in C++ but not in C. */
递增和递减运算符类似于赋值,因为它们可以修改参数。
在C++03中,(++a)--
会导致未定义的行为,因为两个没有按顺序排列的操作正在修改同一个变量。(即使一个是"pre",一个是是"post",但它们是未排序的,因为没有,
、&&
、?
等。)
在C++11中,表达式现在执行您所期望的操作。但C11并没有改变任何这样的规则,这是一个语法错误。
对于任何可能想要标准中所述差异的精确细节的人,C99§6.5.3/2说:
前缀++运算符的操作数的值递增。结果是新的递增后操作数的值。
相比之下,C++11,§5.3.2/1说:
结果是更新的操作数;它是一个左值,如果操作数是一个位字段。
[在这两种情况下都增加了强调]
还要注意,虽然(++a)--
在a
是int
时给出了未定义的行为(至少在C++03中是这样),但如果a
是某种用户定义的类型,因此您使用自己的++
和--
重载,则行为将被定义——在这种情况下,您将得到等效的:
a.operator++().operator--(0);
由于每个操作符都会导致一个函数调用(不能重叠),因此实际上确实有序列点来强制定义行为(注意,我不建议使用它,只是注意在这种情况下行为实际上是定义的)。
§5.2.7增量和减量:
后置
++
表达式的值是其操作数的值[…] 操作数应为可修改的左值。
您在C编译中遇到的错误有助于表明这只是C++中的一个功能。
- 欧拉项目#8答案是大以获得有效答案
- 调整大小后指向元素值的指针unordered_map有效?
- 为什么是0;C++中的有效语句
- 最高有效数字侧的第N位
- GCC对可能有效的代码抛出init list生存期警告
- 有效地使用std::unordered_map来插入或增加键的值
- c++中O(n^(1/3))中一个数的除数的有效计数
- 使用无符号字符数组有效存储内存
- 自定义先决条件对移动分配运算符有效吗
- 为什么将值返回函数传递给重载=运算符对运算符函数有效,而对其他运算符无效
- 有哪些有效的方法可以消除一组 100 万个字符串>重复数据?
- 为什么这种直接初始化有效?(C++17)
- 递归函数有效,但无法记忆
- 在C++中初始化向量映射的最有效方法
- 如果变量名称不跟在 char* 后面,const char* 是否有效?
- 钳制迭代器是否有效
- 如何有效地在 std::vector 中插入一对?
- C++模板 t 不是有效的模板类型
- 检查由括号、方括号和大括号组成的一组方括号是否有效?
- 将此布尔值传递给此函数的最有效方法是什么?