`pow`和`floor`未定义的引用错误

143

我正在尝试在C语言中制作一个简单的斐波那契计算器,但是当我编译时,gcc告诉我缺少powfloor函数。这是怎么回事?

代码:

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

int fibo(int n);

int main() {
        printf("Fib(4) = %d", fibo(4));
        return 0;
}

int fibo(int n) {
        double phi = 1.61803399;

        return (int)(floor((float)(pow(phi, n) / sqrt(5)) + .5f));
}

输出:

gab@testvm:~/work/c/fibo$ gcc fib.c -o fibo
/tmp/ccNSjm4q.o: In function `fibo':
fib.c:(.text+0x4a): undefined reference to `pow'
fib.c:(.text+0x68): undefined reference to `floor'
collect2: ld returned 1 exit status

由于浮点精度不是无限的,因此对于不太大的n值,这将给出错误的答案。 - vonbrand
可能是undefined reference to sqrt (or other mathematical functions)的重复问题。 - Toby Speight
似乎存在一种更简单的解决方案,只需使用g++:g++ fib.c -o fibo - OrenIshShalom
6个回答

274

你需要使用链接标志-lm进行编译,就像这样:

gcc fib.c -lm -o fibo

这将告诉gcc链接您的代码到数学库。请确保在要链接的对象之后放置标志。


9
可以请你解释一下如何确定加在“-l”后面的字母吗? - kettlepot
52
请查看/lib或/usr/lib目录。所有库的名称都是“lib<name>.a”或“lib<name>.so”,其中“<name>”是你在“-l”后面加上的内容。在这种情况下,数学库的名称为“libm.so”,因此我们使用“-lm”来调用它。 - ams
4
谢谢!我已经Google了30分钟,这是第一个提到在对象之后链接库的参考资料。 - Dave Baghdanov
1
作为对 @GabrieleCirulli 的评论的回应(很久以前的评论,现在才@你,抱歉!),我想补充一下另一种找到这个信息的方法,那就是查看相关函数的 man 手册,特别是手册第 3 部分 -- 即输入 man 3 floor 和/或 man 3 pow,它们都应该提到 -lm 链接器标志。 - lindes
1
@KenIngram:看起来像是C++版本的头文件...对于C++是有效的,但非C++的C编译器可能会在此处出现问题(对我而言,gcc就有问题,尽管g++可以很好地处理它)。 - lindes
显示剩余5条评论

26
将-lm添加到您的链接选项中,因为pow()和floor()函数是数学库的一部分。
gcc fib.c -o fibo -lm

10

为了日后阅读方便,您需要像Fred所说的那样进行链接:

gcc fib.c -lm -o fibo

找到需要链接的库的一种好方法是检查 man 页面(如果存在)。例如,man powman floor 都会告诉你:

需要链接 -lm

C 编程中链接数学库的解释 - 链接 C 程序


9

关于Fuzzy提供的答案:

实际上,我需要做一些稍微不同的事情。

项目 -> 属性 -> C/C++构建 -> 设置 -> GCC C链接器 -> 库

点击小绿色添加图标,输入m并点击确定。在这个窗口中的所有内容都自动应用了-l,因为它是一个库。


7

在Eclipse-IDE中找到添加-lm的位置真的很困难,所以我花了一些时间。

如果其他人也使用Eclipse,以下是添加命令的方法:

项目 -> 属性 -> C / C ++构建 -> 设置 -> GCC C链接器 -> 其他选项 -> 链接器标志:在此字段中添加命令-lm。


4
上面所有的回答都不完整,这里的问题在于链接器ld而不是编译器collect2: ld returned 1 exit status。当你将fib.c编译为目标文件时:
$ gcc -c fib.c
$ nm fib.o
0000000000000028 T fibo
                 U floor
                 U _GLOBAL_OFFSET_TABLE_
0000000000000000 T main
                 U pow
                 U printf

其中,nm 列出目标文件中的符号。您可以看到它已经编译成功,但是 pow, floor, 和 printf 函数存在未定义的引用。如果我尝试将其链接到可执行文件:

$ gcc fib.o
fib.o: In function `fibo':
fib.c:(.text+0x57): undefined reference to `pow'
fib.c:(.text+0x84): undefined reference to `floor'
collect2: error: ld returned 1 exit status

我得到了与你相似的输出。为了解决这个问题,我需要告诉连接器在哪里查找对powfloor的引用,为此我将使用连接器-l标志,并使用m来自libm.so库。

$ gcc fib.o -lm
$ nm a.out
0000000000201010 B __bss_start
0000000000201010 b completed.7697
                 w __cxa_finalize@@GLIBC_2.2.5
0000000000201000 D __data_start
0000000000201000 W data_start
0000000000000620 t deregister_tm_clones
00000000000006b0 t __do_global_dtors_aux
0000000000200da0 t 
__do_global_dtors_aux_fini_array_entry
0000000000201008 D __dso_handle
0000000000200da8 d _DYNAMIC
0000000000201010 D _edata
0000000000201018 B _end
0000000000000722 T fibo
0000000000000804 T _fini
                 U floor@@GLIBC_2.2.5
00000000000006f0 t frame_dummy
0000000000200d98 t __frame_dummy_init_array_entry
00000000000009a4 r __FRAME_END__
0000000000200fa8 d _GLOBAL_OFFSET_TABLE_
                 w __gmon_start__
000000000000083c r __GNU_EH_FRAME_HDR
0000000000000588 T _init
0000000000200da0 t __init_array_end
0000000000200d98 t __init_array_start
0000000000000810 R _IO_stdin_used
                 w _ITM_deregisterTMCloneTable
                 w _ITM_registerTMCloneTable
0000000000000800 T __libc_csu_fini
0000000000000790 T __libc_csu_init
                 U __libc_start_main@@GLIBC_2.2.5
00000000000006fa T main
                 U pow@@GLIBC_2.2.5
                 U printf@@GLIBC_2.2.5
0000000000000660 t register_tm_clones
00000000000005f0 T _start
0000000000201010 D __TMC_END__

现在你可以看到,函数 powfloorGLIBC_2.2.5 相关联。

参数的顺序也很重要,除非你的系统默认使用共享库,我的系统不是这样配置的,所以当我输入以下命令:

$ gcc -lm fib.o
fib.o: In function `fibo':
fib.c:(.text+0x57): undefined reference to `pow'
fib.c:(.text+0x84): undefined reference to `floor'
collect2: error: ld returned 1 exit status

注意在目标文件之前加上-lm 标志。因此,总之,在添加所有其他标志和参数后,要确保在最后加上-lm 标志。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接