圆括号和赋值运算符顺序
Parenthesis and assignment operator order
我正在编写c表达式解析器,发现了我不理解的行为:
#include <iostream>
#include <sstream>
int main()
{
std::string string1;
std::string string2 = std::string((string1 = std::string("first")) + " " + (string1 = std::string("second")));
std::cout << string1 << std::endl;
std::cout << string2 << std::endl;
int int1;
int int2 = (int1 = 1) + (int1 = 2);
std::cout << int1 << std::endl;
std::cout << int2 << std::endl;
std::cin.get();
return 0;
}
输出:
first
first first
2
4
我期待:
second
first second
2
3
当在C#中运行相同的程序时,我得到了预期的输出。你能解释一下那里到底发生了什么吗?
C#代码:https://gist.github.com/Kukkimonsuta/59543cfc4f7f73b8bebd
此代码在C++中有未定义的行为,因为单个表达式会对同一变量产生多个副作用(即对string1
的两个赋值)。int1
变量也是如此。
在您的情况下,编译器按照与您预期相反的顺序应用这两种副作用。即使它确实按照您期望的顺序应用了它们,该程序仍然无效。
当在C#中运行相同的程序时,我得到了预期的输出。
与C++不同,C#不会让编译器开发人员做出太多决定。这些表达式以及在C++中产生未定义行为的许多其他表达式的求值顺序是由语言标准很好地定义的。
这是C和C++中未定义的行为。变量int1
在同一语句中被多次修改。
参见序列点:
一个经常被引用的例子是C表达式
i=i++
,它显然既给i
赋值,又增加i
。。。。在C和C++中,对这样的表达式求值会产生未定义的行为
脚注:
C99规范第6.5条第2款:"在上一个和下一个序列点之间,对象的存储值应通过表达式的求值最多修改一次。此外,只能访问先前的值来确定要存储的值。"
除此之外,假设我们有不同的变量,结果仍然无法保证。与C#相反,C++没有指定表达式各部分的求值顺序。
相关文章:
- 重载Singly Linked List中的赋值运算符
- 使用赋值运算符重载从类中返回jobject
- 标准库类型的赋值运算符的引用限定符
- 复制构造函数、赋值运算符C++
- 标准::变体的赋值运算符
- 移动赋值运算符;尝试引用已删除的函数.我该如何解决这个问题?
- 基类和派生类的多态赋值运算符
- 为用户定义的类正确调用复制构造函数/赋值运算符
- CRTP 中的复制赋值运算符 - gcc vs clang 和 msvc
- 为什么初始化时没有调用重载赋值运算符?
- 赋值运算符重载和自赋值
- C++矢量复制构造函数和赋值运算符是否也复制保留空间?
- Qt PL/SQL - 赋值运算符 - 字符串缓冲区太小
- 对 r 值使用移动赋值运算符时的异常
- 由于没有使用赋值运算符,映射的值是如何初始化的?
- 默认赋值运算符如何在实际 STL 中实现
- 使用赋值运算符复制 std::vector
- C++ 通过自定义赋值运算符隐式转换函数参数
- 双向循环列表中的赋值运算符以错误的顺序添加元素
- 圆括号和赋值运算符顺序