圆括号和赋值运算符顺序

Parenthesis and assignment operator order

本文关键字:顺序 赋值运算符 圆括号      更新时间:2023-10-16

我正在编写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++没有指定表达式各部分的求值顺序。