【问题标题】:why is the value of a variable printed from my c program different from that printed by gdb?为什么我的 c 程序打印的变量值与 gdb 打印的变量值不同?
【发布时间】:2011-12-09 00:53:04
【问题描述】:

我正在使用 gcc44 和 gdb 调试在 64 位 Linux CentOS 5.7 上运行的 ANSI C 程序。我在程序中有以下循环:

for (ii = 1; ii < 10001; ii++) {
    time_sec[ii] = ( 10326 ) * dt - UI0_offset;  /* in seconds */ 
    printf("\ntime_sec[%d] = %16.15e, dt = %16.15e, UI0_offset = %26.25e\n", 
           ii, time_sec[ii], dt, UI0_offset);
}

其中 time_sec、dt 和 UI0_offset 是双精度数。相关的 gdb 会话是:

(gdb) p time_sec[1]
$2 = 2.9874137906250006e-15
(gdb) p ( 10326 ) * dt - UI0_offset
$3 = 2.9874137906120759e-15

为什么 $2 和 $3 是不同的数字? $2=time_sec[1] 由 c 程序计算,而 $3 是相同的等式,但在 gdb 中计算。

我将一个 Matlab 算法移植到 C 和 Matlab(在不同的机器上运行)与 gdb 数字 $3 完全匹配,我需要这个精度。任何人都知道这里可能发生了什么,以及如何解决?

更新:经过一些调试,似乎区别在于 UI0_offset 的值。我探查 gdb 以显示该变量的一些额外数字(注意:有人知道在 gdb 中查看更多数字的更好方法吗?我尝试了 sprintf 语句但无法使其工作):

(gdb) p UI0_offset -1e-10
$5 = 3.2570125862093849e-12

然后我在上面原始帖子中显示的循环中插入了 printf() 代码,当它在 gdb 中运行时显示:

time_sec[1] = 2.987413790625001e-15, dt = 1.000000000000000e-14, 
UI0_offset = 1.0325701258620937565691357e-10

因此,总结一下:

1.032570125862093849e-10 (from gdb command line, the correct value)
1.0325701258620937565691357e-10 (from program's printf statement, NOT correct value)

任何理论为什么 gdb 命令行和在 gdb 中运行的程序之间的 UI0_offset 的值不同(以及,如何使程序与 gdb 命令行一致)?

【问题讨论】:

  • 使用 gcc 编译应用程序时使用的优​​化级别是什么?
  • 我什么都没说,所以不管是默认的。编译持续时间对我来说不是问题。我应该使用 -O2 吗?
  • 你能给我们展示一个展示这个问题的完整的小程序吗?例如,您向我们展示的结果仅指time_sec[1];您不需要计算其他 10000 个值来演示问题。尝试将您的代码缩小到声明和初始化相关变量的内容,并向我们展示我们可以自己尝试的内容。 (事实上​​,我不知道time_secdtUI0_offset 的值是什么。)
  • 我尝试使用 -O2 优化,但没有任何改善。

标签: c gdb


【解决方案1】:

我不确定 x64 架构是否包含与 x86 相同的 80 位(long double)FP 寄存器,但在 x86 世界中,当中间结果(即第一次乘法)保留在80 位寄存器,而不是被刷新回高速缓存/RAM。实际上,您的部分计算是以更高的精度完成的,因此会产生不同的结果。

GCC 有一个选项(-ffloat-store,如果我没记错的话)会导致中间结果刷新回 64 位精度。尝试启用它,看看你是否匹配 GDB/Matlab 结果。

【讨论】:

  • 嗯,我得到编译错误:gcc44:无法识别的选项“-store”,其中四个:cc1:错误:无法识别的命令行选项“-ffloat”。放置顺序重要吗?我正在使用,# gcc44 -g -ansi -ffloat -store infile.c -o out -lm
  • @ggkmath:这是一种选择,-ffloat-store('t' 和 '-' 之间没有空格)。
  • 哦,我的错。好的,现在可以编译了,但我看到的结果完全相同(没有任何变化)。
  • @ggkmath:太糟糕了。然后,您可以尝试以下方法:-msse2 -mfpmath=sse。这将强制所有 FP 数学使用 64 位 SSE 寄存器(即没有 80 位路径)。如果那不这样做,我认为我的理论被打破了,你需要看看其他的 FP 优化选项。
  • 感谢 Drew,我尝试使用这些开关,仍然得到完全相同的结果(没有变化)。我的印象是双精度在小数点后有 31 位精度,好吧,只是因为我可以打印它们并查看它们。但是,现在我在想,也许第 16 位之后的那些数字不应该被认为是准确的。
猜你喜欢
  • 2011-11-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-10-25
  • 2011-09-06
相关资源
最近更新 更多