sqrt из math.h вызывает ошибку компоновщика неопределенной ссылки на sqrt только в том случае, если аргумент не является константой

Я создал небольшую программу следующим образом:

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

  int main(int argc, char *argv[]) {
    int i; 
    double tmp;
    double xx;

    for(i = 1; i <= 30; i++) {
      xx = (double) i + 0.01;

      tmp = sqrt(xx);
      printf("the square root of %0.4f is %0.4f\n", xx,tmp);
      sleep(1);
      xx = 0;
    }

    return 0;
 }

Когда я пытаюсь скомпилировать это с помощью следующей команды, я получаю ошибку компилятора.

gcc -Wall calc.c -o calc

возвращает:

/tmp/ccavWTUB.o: In function `main':
calc.c:(.text+0x4f): undefined reference to `sqrt'
collect2: ld returned 1 exit status

Если я заменю переменную в вызове sqrt(xx) на константу типа sqrt(10.2), компилируется просто отлично. Или, если я явно ссылаюсь следующим образом:

gcc -Wall -lm calc.c -o calc

Он также отлично работает. Может ли кто-нибудь сказать мне, что вызывает это? Я долгое время был программистом на C (и я писал подобные небольшие программы, используя math.h), и я никогда не видел ничего подобного.

Моя версия gcc выглядит следующим образом:

$ gcc --version
gcc (Ubuntu 4.3.3-5ubuntu4) 4.3.3
Copyright (C) 2008 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
$

person alesplin    schedule 10.11.2009    source источник
comment
Нужен ли -lm, если вы укажете --std=c99?   -  person György Andrasek    schedule 11.11.2009
comment
Ага. Странный. Я также пытался использовать -ansi для того же эффекта. Нет без -lm   -  person alesplin    schedule 11.11.2009
comment
Интересная особенность gcc заключается в том, что вам нужно явно связать математическую библиотеку — это сразу бросается в глаза. То, что компилятор может незаметно заменить sqrt(10.2), только добавляет удовольствия!   -  person Martin Beckett    schedule 11.11.2009
comment
Что бы это ни стоило, это не ошибка компилятора, это ошибка компоновщика.   -  person Carl Norum    schedule 11.11.2009
comment
Более общий вопрос без наблюдения sqrt(CTE): stackoverflow.com/questions/5248919/   -  person Ciro Santilli 新疆再教育营六四事件ۍ    schedule 15.05.2015


Ответы (1)


Если вы посмотрите на вывод компилятора в случае, когда вы использовали sqrt(10.2), держу пари, вы увидите, что вызов sqrt() на самом деле не был сделан.

Это происходит потому, что GCC распознает несколько функций, которые он может обрабатывать особым образом. Это дает ему возможность выполнять определенные оптимизации, в данном случае константное свертывание. Такие специальные функции называются встроенными.

В случае, когда он должен ссылаться на математическую библиотеку (поскольку вы вызываете его с помощью переменной), вам нужно связать его явно. Некоторые операционные системы/компиляторы делают это за вас, поэтому раньше вы могли этого не замечать.

person Carl Norum    schedule 10.11.2009
comment
+1 Многие системы автоматически связываются с математической библиотекой для вас. Некоторые этого не делают. Твой нет. - person Stephen Canon; 11.11.2009
comment
Я думаю, что он пытается сказать, что если вы возьмете sqrt константы, результат также будет константой, поэтому компилятор сделает это за вас во время компиляции, не оставляя вызовов sqrt в коде, так что вы не будете необходимо связать с libm (-lm) ​​во время компоновки. - person Southern Hospitality; 11.11.2009
comment
Спасибо, парни. Я собираюсь попробовать это на своем Mac, когда вернусь домой, и посмотрю, что произойдет. - person alesplin; 11.11.2009
comment
Вам не нужен -lm на Mac. Ну, по крайней мере, не на той, которую я использую сейчас. - person Carl Norum; 11.11.2009
comment
@CarlNorum, какой компилятор вы используете? - person LunaticNeko; 13.09.2012
comment
В 2009 году это, вероятно, был GCC. - person Carl Norum; 29.04.2013