2009-11-10 49 views
6

我创建一个小程序,如下所示:SQRT导致连接错误“未定义参照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)与像开方(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. 
$ 
+0

如果指定'--std = c99',它仍然需要'-lm'吗? – 2009-11-10 23:15:28

+0

是的。奇怪的。我也尝试使用-ansi来达到同样的效果。 No-go without -lm – alesplin 2009-11-10 23:22:18

+4

这是gcc的一个有趣功能,您需要明确链接数学库 - 它首次吸引了所有人。 编译器可以静静地替换sqrt(10.2),只是增加了乐趣! – 2009-11-10 23:25:20

回答

16

如果你看一下在您使用sqrt(10.2)的情况下,编译器的输出,我敢打赌,你看到到sqrt()呼叫未曾作过。

发生这种情况是因为GCC认识到它可以专门处理的几项功能。这使其有能力做一些优化,在这种情况下,Constant folding。这种特殊功能称为Built-ins

如果它必须链接到数学库(因为您使用变量调用它),则需要明确链接它。有些操作系统/编译器会为你做,这就是你以前可能没有注意到的原因。

+2

+1许多系统自动与你的数学库链接。有些不。你的不是。 – 2009-11-10 23:20:32

+11

我想他想说的是,如果你使用常量的sqrt,结果也是一个常量,所以编译器会在编译时为你做,而不会在代码中调用sqrt,在链接时需要链接到libm(-lm)。 – 2009-11-10 23:20:35

+0

南方酒店管理有限。 – 2009-11-10 23:26:41