GCC:在同一指令上使用相同的 var 时引用参数更改

gcc: reference parameter change when using the same var on the same instruction

本文关键字:var 引用 参数 指令 GCC      更新时间:2023-10-16

我指出了一个奇怪的gcc行为:当同一指令使用相同的变量,并且当此变量由一个函数调用(通过引用或指针传递的变量)修改时,不会为同一指令的其他函数修改变量更改。

这是正常的 c++ 行为还是博古斯?
注: 未设置优化 (-O) 标志。
注意 2:这在 solaris CC 编译器中工作正常。

使用 gcc 4.5.3 演示(在 Linux 或 mingw/cygwin 上)

class C {
public:
  const C & inc(int & i) const       
  {
     ++i;
     cout << "inc: i = " << i << endl; return *this;
  }
  const C & see(int i) const   
  {     
     cout << "see: i = " << i << endl; return *this; 
  }
  const C & see2(const int & i) const {  
    cout << "see2: i = " << i << endl; return *this; }
  };
int main()
{
  C c;
  int i = 0;
  c.see(i).inc(i).see(i).see2(i).inc(i).see(i).see2(i);
  c.see(i);
  return 0;
}

输出:

参见:i = 0
公司: i = 1
参见: i = 0 : 1 预期
参见 2: i = 1
公司: i = 2
参见: i = 0 : 2 预期
参见 2: i = 2
参见:i = 2

函数参数的求值顺序彼此不确定。 在这种情况下,gcc 选择提前评估传递给see方法调用i

您的代码等效于:

class C {};
C &inc(C &c, int &i) { ++i; return c; }
C &see(C &c, int i) { std::cout << i << 'n'; return c; }
C c;
int i = 0;
see(inc(c, i), i);

see参数的有效求值顺序为:

1. evaluate inc(...) to pass c to see(...)
2. evaluate i as an rvalue to pass to see(...)
1. evaluate i as an rvalue to pass to see(...)
2. evaluate inc(...) to pass c to see(...)

在前一种情况下,程序打印1;在后者中,它打印0

请注意,行为是未指定的,但不是未定义的;它必须打印01。 这是因为序列点在调用inc之前和之后获取;在 C++11 中,函数的执行相对于调用函数中的计算是不确定排序的(但不是未排序的)(1.9p15)。

这是正确的行为:它不是由标准指定的,给定语句的子表达式的执行顺序。显然,在您的情况下,编译器首先执行所有i子表达式,即制作i的副本以将它们传递给不同的see()调用,然后再inc()调用进行评估。