Почему gdb оценивает sqrt (3) на 0? - программирование
Подтвердить что ты не робот

Почему gdb оценивает sqrt (3) на 0?

Квадратный корень из 3, по оценкам Wolfram Alpha:

1.7320508075688772935274463415058723669428052538103806280558...

Когда я делаю sqrt(3) в C, он вычисляет 0. Почему?

EDIT4: вот как вы можете воспроизвести эту проблему в GDB. Создайте test.c следующим образом:

#include <stdio.h>                                                                                                                                                                      
#include <math.h>

int main()
{
  printf("sqrt(3): %f\n", sqrt(3));
  return 0;
}

Compile:

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).

4b9b3361

Ответ 1

Проблема заключается не в отсутствующем объявлении функции (который отсутствует, так как вы включили <math.h>).

Проблема заключается в отсутствии информации об отладке для sqrt, которую вы фактически используете. Без этой информации об отладке GDB не знает, какой тип параметра должен перейти к sqrt(), и что он возвращает.

Вы можете получить требуемую информацию об отладке во многих дистрибутивах Linux, установив пакет libc-debuginfo. Вот что я вижу в такой системе:

gdb -q ./a.out
Reading symbols from /tmp/a.out...done.
(gdb) b main
Breakpoint 1 at 0x400558: file t.c, line 6.
(gdb) r

Breakpoint 1, main () at t.c:6
6     printf("sqrt(3): %f\n", sqrt(3));
(gdb) p sqrt
$1 = {<text variable, no debug info>} 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, но GDB знает его тип!

(gdb) p __sqrt(3)
$5 = 1.7320508075688772
(gdb) p __sqrt(3.0)
$6 = 1.7320508075688772

Можно обоснованно утверждать, что это ошибка в GDB. Не стесняйтесь создавать его в GDB bugzilla.

Ответ 2

Я предсказываю, что вы не сделали #include <math.h>

Без объявления функции C по умолчанию возвращается значение функции int. Число с плавающей запятой может возвращаться как 0 в зависимости от размера вашего int. C также не знает, как преобразовать аргумент функции. Он по умолчанию передаст аргумент как любой тип, которым он является. Если вы передадите целое число в sqrt(), он не будет преобразован в double, но функция sqrt() будет интерпретировать битовый шаблон как double.

Ответ 3

#include <stdio.h>                                                                                                                                                                      
#include <math.h>

int main()
{
  printf("sqrt(3): %f\n", sqrt(3));

  return 0;
}

Вывод:

[email protected]:~/scratch$ ./a.out 
sqrt(3): 1.732051

Ответ 4

Может быть, вызов sqrt не поддерживается! Может быть, потому что это функция libc. Я не знаю глубинную причину, но следующий тест показывает интересное поведение:

double mysqrt(double x) { return sqrt(x) };

Затем в сеансе gdb:

(gdb) p mysqrt(3)
$1 = 1.7320508075688772
(gdb) p sqrt(3)
$2 = -1209775368

Ответ 5

Чтобы вызвать функцию без информации об отладке, вы должны явно указать gdb тип возвращаемого значения и аргументы, используя функцию-указатель функции. Итак, для вашего примера:

(gdb) print ((double (*) (double)) sqrt) (3)
$1 = 1.7320508075688772