Почему функция sqrt не работает для значений, введенных пользователем?

Следующий код:

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

int main(void)
{
    long long int a;
    scanf("%lld", &a);
    printf("%lf", sqrt(a));
    return 0;
}

дает вывод:

source_file.c: In function ‘main’:
source_file.c:9:5: warning: ignoring return value of ‘scanf’, declared with attribute warn_unused_result [-Wunused-result]
     scanf("%lld", &a);
     ^
/tmp/ccWNm2Vs.o: In function `main':
source.c:(.text.startup+0x65): undefined reference to `sqrt'
collect2: error: ld returned 1 exit status

Однако, если я делаю long long int a = 25; и удаляю оператор scanf, или просто делаю sqrt(25), оба они работают (правильно дают вывод 5.000000).

Я проверил этот вопрос, но он для C++ и использует перегрузку функций, тогда как afaict C не имеет перегрузки функций (поэтому у нас есть sqrtf, sqrt, sqrtl, если я не ошибаюсь). Более того, приведенный выше код не работает независимо от того, беру ли я long long int или double тип a. Таким образом, вопросы, вероятно, не связаны.
Кроме того, что касается другого связанного вопроса, у меня не возникала ошибка для постоянно определенные значения, что вместо этого имеет место со связанным вопросом.

В чем тогда причина? Почему постоянное значение будет работать для sqrt, а переменное значение пользовательского ввода - нет?


person Gaurang Tandon    schedule 28.10.2018    source источник
comment
У вас есть связь с -lm Например, gcc -Wall test.c -lm?   -  person Achal    schedule 28.10.2018
comment
Это давняя ошибка gcc (также известная как странное дизайнерское решение)   -  person M.M    schedule 28.10.2018
comment
@Achal Да, я пытался, все равно не работает :(   -  person Gaurang Tandon    schedule 28.10.2018
comment
покажите точную команду сборки и версию gcc   -  person M.M    schedule 28.10.2018
comment
Также вы должны -std=c99 (или позже, например, -std=c11), так как используете long long   -  person M.M    schedule 28.10.2018
comment
@M.M -Wall -lm -std=gnu99 -O2 -o a.out source_file.c Я также безуспешно пытался использовать -Wall -lm -o a.out source_file.c.   -  person Gaurang Tandon    schedule 28.10.2018
comment
@GaurangTandon -lm должен стоять в конце, как предложил Ачал   -  person M.M    schedule 28.10.2018
comment
@M.M О, хорошо, это сработало. Спасибо!   -  person Gaurang Tandon    schedule 28.10.2018
comment
@GaurangTandon Я подробно объяснил постоянный случай в этом ответе   -  person Antti Haapala    schedule 28.10.2018
comment
Когда в комментарии указывается, что требуется дополнительная информация, эта информация должна быть добавлена ​​к вопросу, а не скрыта в комментарии. Отредактируйте вопрос, чтобы добавить разъяснения, подробности расследования, попытки решения и дополнительную диагностическую информацию.   -  person Clifford    schedule 28.10.2018


Ответы (2)


Как упоминалось в комментариях, вы не связались с libm, поэтому sqrt не определено во время компоновки.

Почему постоянное значение будет работать для sqrt, а переменное значение пользовательского ввода - нет?

Поскольку GCC распознает sqrt как встроенную функцию и может оценить квадратный корень из константы времени компиляции во время компиляции и полностью отказывается от вызова sqrt, тем самым избегая последующей ошибки компоновщика.

Функции ISO C90 ... sqrt, ... распознаются как встроенные функции, если не указана -fno-builtin (или не указана -fno-builtin-function для отдельной функции).

Если бы вы добавили -fno-builtin-sqrt, вы бы увидели ошибку компоновщика независимо от того, что вы передаете sqrt.

person Jonathon Reinhart    schedule 28.10.2018

Функции внутри stdlib.h и stdio.h имеют реализации в libc.so (или libc.a для статической компоновки), которые по умолчанию компонуются в исполняемый файл (как если бы были указаны -lc).

GCC можно указать избегать этой автоматической ссылки с параметрами -nostdlib или -nodefaultlibs.

Функции в math.h имеют реализации в libm.so (или libm.a для статической компоновки), а libm по умолчанию не компонуется.

По сути, среда выполнения C++ libstdc++ требует libm, поэтому, если вы скомпилируете программу на C++ с помощью GCC (g++), вы автоматически получите libm.

person Md. Mokammal Hossen Farnan    schedule 28.10.2018