为什么gdb将sqrt(3)评估为0?
由Wolfram Alpha估算的3的平方根:
1.7320508075688772935274463415058723669428052538103806280558...
当我在C中执行sqrt(3)
时,它的计算结果为0.为什么?
编辑4 :这是你如何在GDB中重现这个问题。 创建test.c
如下:
#include #include int main() { printf("sqrt(3): %f\n", sqrt(3)); return 0; }
编译:
gcc -O0 -g -Wall -pedantic -ansi -lm -o test test.c
运行调试器:
gdb test
在控制台输入:
(gdb) break test.c:6 Breakpoint 1 at 0x400578: file test.c, line 6. (gdb) r Starting program: /home/pdedecker/Desktop/test Breakpoint 1, main () at test.c:6 6 printf("sqrt(3): %f\n", sqrt(3)); (gdb) print sqrt(3) $1 = 0 (gdb) s sqrt(3): 1.732051
我的GDB版本是GNU gdb (GDB) SUSE (7.1-3.12)
。
问题不在于缺少的函数声明(由于你确实包含了
,因此不会丢失)。
问题是缺少您实际使用的sqrt
调试信息。 没有那个调试信息,GDB不知道要传递给sqrt()
参数类型,以及它返回的内容。
您可以通过安装libc-debuginfo软件包在许多Linux发行版上获得所需的调试信息。 这是我在这样一个系统上看到的:
gdb -q ./a.out Reading symbols from /tmp/a.out...done. (gdb) b main Breakpoint 1 at 0x400558: file tc, line 6. (gdb) r Breakpoint 1, main () at tc:6 6 printf("sqrt(3): %f\n", sqrt(3)); (gdb) p sqrt $1 = {} 0x7ffff7b7fb50 <__sqrt>
注意:“没有调试信息”
(gdb) p sqrt(3) $2 = 0 (gdb) p sqrt(3.0) $3 = 0
注意:符合您的行为。 什么sqrt
函数有调试信息?
(gdb) info func sqrt All functions matching regular expression "sqrt": File ../sysdeps/x86_64/fpu/e_sqrt.c: double __ieee754_sqrt(double); File s_csqrt.c: complex double __csqrt(complex double); File ../sysdeps/x86_64/fpu/e_sqrtf.c: float __ieee754_sqrtf(float); File w_sqrtf.c: float __sqrtf(float); File s_csqrtf.c: complex float __csqrtf(complex float); File ../sysdeps/i386/fpu/e_sqrtl.c: long double __ieee754_sqrtl(long double); File w_sqrtl.c: long double __sqrtl(long double); File s_csqrtl.c: complex long double __csqrtl(complex long double); File ../sysdeps/ieee754/dbl-64/mpsqrt.c: void __mpsqrt(mp_no *, mp_no *, int); File w_sqrt.c: double __sqrt(double); (gdb) p __sqrt $4 = {double (double)} 0x7ffff7b7fb50 <__sqrt>
注意: __sqrt
sqrt
与sqrt
地址相同,但GDB知道它的类型!
(gdb) p __sqrt(3) $5 = 1.7320508075688772 (gdb) p __sqrt(3.0) $6 = 1.7320508075688772
可以合理地说这是GDB中的一个错误。 随意在GDB bugzilla中创建一个。
我预测你没有做#include
如果没有函数声明,C将默认函数的返回值为int
。 浮点数可能会返回0,具体取决于int的大小。 C也不知道如何转换函数参数。 它将默认将参数传递为它碰巧的类型。 如果将整数传递给sqrt()
,则不会将其转换为double,但sqrt()
函数会将位模式解释为double
。
要调用没有调试信息的函数,必须使用函数指针强制显式告诉gdb返回和参数的类型。 所以,举个例子:
(gdb) print ((double (*) (double)) sqrt) (3) $1 = 1.7320508075688772
#include #include int main() { printf("sqrt(3): %f\n", sqrt(3)); return 0; }
输出:
josh@josh-ubuntu:~/scratch$ ./a.out sqrt(3): 1.732051
也许不支持调用sqrt! 也许是因为它是一个libc函数。 我不知道其深层原因,但以下测试显示了一个有趣的行为:
double mysqrt(double x) { return sqrt(x) };
然后在gdb会话中:
(gdb) p mysqrt(3) $1 = 1.7320508075688772 (gdb) p sqrt(3) $2 = -1209775368