G++与Clang++编译器的C++运算符优先级差异问题咨询
问题分析:G与Clang对自定义类型运算符表达式的输出差异
1. 内置类型部分的一致行为
对于代码中的内置类型表达式:
int y = myINT++ + myINT * 2;
C++17及以后的标准明确规定,加法运算符的左操作数会先于右操作数完全求值。执行顺序为:
- 先计算
myINT++,返回值3,myINT变为4 - 再计算
myINT * 2,即4*2=8 - 最终
y = 3 + 8 = 11,myINT的值为4
这也是两个编译器输出11 4的原因,行为一致且符合标准。
2. 自定义类型部分的差异根源
问题出在自定义类型A的表达式:
y = myA++ + myA * 2;
自定义类型的运算符重载本质是函数调用,上述表达式等价于(myA++).operator+(myA * 2)(因operator+是成员函数)。
关键:求值顺序的标准规定
- C++17之前:函数调用中,对象表达式(此处为
myA++)和参数表达式(此处为myA * 2)的求值顺序是未指定的,编译器可自由选择先计算哪一项。 - C++17及以后:标准明确要求,成员函数调用的对象表达式必须先于参数表达式求值,即必须先计算
myA++,再计算myA * 2。
两种编译器的执行逻辑
Clang的行为(符合C17及以后标准)
- 先计算
myA++:返回临时对象A(3),myA.a变为4 - 再计算
myA * 2:myA.a从4变为8(operator*直接修改自身) - 调用
operator+:临时对象的a加上myA.a(8),变为3+8=11,转换为int后y=11 - 最终
myA.a的值是8
对应输出:11 8
G的行为(符合C17之前的未指定顺序,不符合C++17及以后)
- 先计算
myA * 2:myA.a从3变为6 - 再计算
myA++:返回临时对象A(6),myA.a变为7 - 调用
operator+:临时对象的a加上myA.a(7),变为6+7=13,转换为int后y=13 - 最终
myA.a的值是7
对应输出:13 7
3. 额外问题:运算符重载的不良实践
你的operator+重载违反了常规语义:它直接修改左操作数的值,而非返回新的临时对象。通常operator+应实现为无副作用的形式:
A operator+(const A& x) const { return A(a + x.a); }
这种实现会让表达式行为更可预测,避免求值顺序带来的差异问题。
内容的提问来源于stack exchange,提问作者Ammar Tamimi
相关产品推荐
相关产品推荐

