如何在C++中查看被优化掉的变量的值?

51

我正在使用gdb来调试一个C++程序。

我有以下代码:

int x = floor(sqrt(3));

我想查看x的值。但是,gdb显示x为"< optimized_out >"。我该如何查看x的值?我需要更改编译器标志吗?


5
如果您没有使用优化编译(即-O0),它应该是可用的。 - Adrian Cornish
7
通常应该使用禁用优化的方式来调试代码。可以使用 -O0 标志来实现这一点。 - Cody Gray
这个回答解决了你的问题吗?在gdb中,<value optimized out>是什么意思? - Akib Azmain Turja
5个回答

59
在高优化级别下,编译器可以消除中间值,正如您在此处所见。有多种选项:
  • 您可以降低优化级别,以使调试器更轻松地跟踪事物。 -O0 肯定能工作(但速度会慢),-O1 也可能工作得不错。
  • 您可以添加一些显式的打印语句来记录输出值。
  • 通常情况下,您还可以通过将其设置为易失性变量来强制编译器保留此特定值(但完成后请记得将其设置为非易失性变量)。然而,请注意,由于控制流也受到优化代码的影响,即使您可以看到变量的值,当您查看相关变量时,可能并不完全清楚当前代码的执行位置。

4
通常情况下,您还可以将函数进行分解,推导出“优化掉”的变量实际所在的寄存器,并打印该变量。目前有开发工作正在进行,以使GCC生成足够详细的调试信息,从而使GDB在未来能够自动执行此操作。 - Employed Russian
1
@EmployedRussian,如果变量确实存在,这可能有效,但是有可能消除计算变量的实际工作,因此并不适用于所有情况。 - bdonlan
局部变量也可以只存在于寄存器中。gcc 可以优化您的代码,使其成为这种方式 - 这是无法查看变量的另一个可能原因。请参阅此答案以了解如何查看寄存器变量:https://dev59.com/LHM_5IYBdhLWcg3wgzhl#1354762 - appas
即使使用 g++ / gdb 的 -O0 选项,对我来说几乎每个变量都被“优化掉”了。编译选项为 -g -fcoroutines -fno-inline -O0 -pthread -std=gnu++2a - Jarrod Smith

18

如果您不能或不想禁用优化,则可以尝试将变量声明为 volatile 。这通常足以使编译器在最终代码中保留变量。

另外,在最近的GCC版本中,您可以像这样仅为函数禁用优化:

void my_function() __attribute__((optimize(0)))
{
  int x = floor(sqrt(3));
}

1
对我来说,这个属性是未定义的。当我使用optnone时,无论如何变量都被优化掉了(clang 3.8)。 - starturtle

4
使用反向调试时,请尝试向变量定义点更接近的位置回溯。如在 What does <value optimized out> mean in gdb? 中所示,通常情况下:

  • 在函数的开头,可以观察到变量的值;
  • 然而,在函数的末尾,变量更有可能变成<optimized out>。由于优化,它只存储在寄存器中,而不是内存堆栈上。因此,当不再需要它时,寄存器很可能被重用并被另一个变量覆盖,然后调试元数据会告知GDB。

因此,如果您使用某种反向调试,例如Mozilla的rr,那么一种好的方法是使用reverse-finish+reverse-next尝试向变量的定义/上次使用的位置回溯,并查看是否能够在那里观察到它。

这可以用What does <value optimized out> mean in gdb?中显示的示例代码具体观察,并且已经多次帮助我解决问题,特别是在运行未优化程序需要太长时间才能到达感兴趣的点时(这并不奇怪,因为-O0生成的汇编代码效率极低)。


1
创建自己的“全局变量”,并将优化后的变量打印到这个全局变量中。确保在调试完成后删除您创建的这些全局变量!

0

使用Visual Studio和VisualGDB扩展的C++中,我看到了语法正确但在运行时变量检查和悬停文本中声称值已被优化的类作用域变量,尽管它们实际上并没有被优化。

为了查看该值,在快速监视或监视窗口中在变量名前缀加上类名即可解决问题。

例如:在myclass中似乎已经被优化掉的myvariable值可以通过myclass::myvariable来查看。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接