sqrt из math.h вызывает ошибку компоновщика «неопределенная ссылка на sqrt», только когда аргумент не является константой - PullRequest
6 голосов
/ 11 ноября 2009

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

  #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

Это также отлично работает. Может кто-нибудь сказать мне, что вызывает это? Я долгое время был программистом на Си (и я писал подобные маленькие программы с использованием 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.
$

1 Ответ

17 голосов
/ 11 ноября 2009

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

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

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

...