为什么 -O3 向下转换/更改对变量的 const 引用的值?

ajo*_*eps 6 c++ c++17

#include <iostream>
#include <stdint.h>

class Test {
  public:
  Test(const int64_t & val) : val_(val) {
    std::cout << "initialized: " << val_ << std::endl;
  }
  void print() {std::cout << "reference val: " << val_ << std::endl;}

  private:
  const int64_t & val_;
};


int main() {
  long long int input_val= 1628020800000000000L;
  auto t = Test(input_val);
  std::cout << "input_val: " << input_val << std::endl; 
  t.print();
}
Run Code Online (Sandbox Code Playgroud)

如果您在没有优化构建的情况下构建,则会得到以下结果:

g++ main.cpp -std=c++17
initialized: 1628020800000000000
input_val: 1628020800000000000
reference val: 1628020800000000000
Run Code Online (Sandbox Code Playgroud)

如果您使用优化构建(例如 -O3)构建,您将获得以下信息:

g++ main.cpp -std=c++17 -O3
initialized: 1628020800000000000
input_val: 1628020800000000000
reference val: 0
Run Code Online (Sandbox Code Playgroud)

我猜这种差异是由于input_valtype的铸造/处理造成的long long int,但我真的不明白为什么会这样。我认为 along至少是 32 位,而 along long至少是long long. 由于参考是 a const int64_t,我认为不会有任何铸造问题。

我意识到如果我切换long long int到 an int64_t,这不会是一个问题,但我想了解为什么会发生这种情况的原因。

g++/gcc 版本:

g++ (GCC) 9.1.1 20190605 (Red Hat 9.1.1-2) Copyright (C) 2019 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
Run Code Online (Sandbox Code Playgroud)

编辑: 此代码的原始版本具有input_val(original static_val) 作为全局静态变量。我将示例更改为更简单,因为问题不是基于变量是全局静态变量。

Mar*_*k R 11

问题是转换。

int64_t与 不同long long int。所以当这个构造函数被调用时:Test(const int64_t & val) 类型的临时值int64_t是从long long int.

所以 resultconst int64_t & val_;持有对生命周期结束之前Test::print被调用的临时对象的引用。Address sanitizer很好地发现了问题

当您统一类型时,它会起作用:https : //godbolt.org/z/nGKa6azE8

注意我添加了检查什么类型int64_t是和它long int在构建 64 位和long long int32 位构建时匹配 。

  • @ajoseps • 这样做是[**未定义的行为**](/sf/answers/287358641/),一旦你有了,一切皆有可能。甚至看起来工作正常。 (6认同)
  • cppreference 说 `int64_t` 是一个 `typedef`,但它的行为是一种与 `long long int` 大小相同的不同类型(在 [godbolt](https://godbolt.org/z/3nrYcexMT) 上)。这对我来说是一个惊喜。 (3认同)
  • 啊……明白了。在这种情况下,“typedef”是“long int”,它具有相同的大小,但类型不同(与“long long int”不同) (2认同)