2009-11-10 4 views
6

ich ein kleines Programm erstellt, wie folgt:sqrt aus math.h verursacht Linkerfehler „undefined reference to sqrt“ nur dann, wenn das Argument nicht eine Konstante ist

#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; 
} 

Wenn ich versuche, dies zu kompilieren mit dem folgenden Befehl, bekomme ich einen Compilerfehler.

gcc -Wall calc.c -o calc 

kehrt:

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

Wenn ich die Variable in dem Aufruf von sqrt (xx) mit einem konstanten wie sqrt (10.2) ersetzen, stellt es nur in Ordnung. Oder, wenn ich explizit wie folgt verbinde:

gcc -Wall -lm calc.c -o calc 

Es funktioniert auch ganz gut. Kann mir jemand sagen, was das verursacht? Ich war lange Zeit ein C-Programmierer (und ich habe ähnliche kleine Programme mit math.h geschrieben) und ich habe noch nie so etwas gesehen.

Meine Version von gcc folgt:

$ 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. 
$ 
+0

Benötigt es '-lm' noch, wenn Sie' --std = c99' angeben? –

+0

Ja. Seltsam. Ich habe auch versucht, -ansi mit demselben Effekt zu verwenden. No-go ohne -lm – alesplin

+4

Es ist ein interessantes Feature von gcc, dass Sie die Mathematikbibliothek explizit verknüpfen müssen - es fängt alle zum ersten Mal aus. Dass der Compiler stillschweigend sqrt (10.2) ersetzen kann, macht einfach Spaß! –

Antwort

16

Wenn Sie am Ausgang des Compilers im Fall schauen, wo Sie sqrt(10.2) verwendet, werde ich Sie darauf wetten, dass ein Anruf an sqrt() eigentlich nicht gemacht .

Das passiert, weil GCC mehrere Funktionen erkennt, die es speziell behandeln kann. Dies gibt ihm die Möglichkeit, bestimmte Optimierungen vorzunehmen, in diesem Fall Constant folding. Solche speziellen Funktionen heißen Built-ins.

In dem Fall, in dem es mit der Mathematikbibliothek verknüpft werden muss (weil Sie es mit einer Variablen aufrufen), müssen Sie es explizit verknüpfen. Einige Betriebssysteme/Compiler tun das für Sie, weshalb Sie es in der Vergangenheit vielleicht nicht bemerkt haben.

+2

+1 Viele Systeme automatisch verlinken Sie gegen die Mathebibliothek für Sie. Manche nicht. Deines nicht. –

+11

Ich denke, was er zu sagen versucht ist, dass, wenn Sie die sqrt einer Konstante nehmen, das Ergebnis auch eine Konstante ist, so dass der Compiler es für Sie zur Kompilierzeit tut, keine Aufrufe an sqrt im Code, so dass Sie nicht ' t müssen zur Zeit der Verbindung gegen libm (-lm) ​​verlinken. –

+0

Southern Hospitality hat es richtig gemacht. –