问题描述
当我尝试编译以下最小示例时,我遇到一个奇怪的问题。对sqrt
的第一次调用没有问题,但是第二个调用引发了我不理解的链接器错误,因为在调用gcc
时确实指定了数学库。当我评论第二行时,它可以正确编译/链接。
代码如下:
// File wtf_sqrt.c
#include <math.h>
int main (int argc,char *argv[]) {
int x = 3; // Just an int...
sqrt(3); // This line works fine
sqrt(x); // But this one seems to give the linker trouble. Why?
return 0;
}
这是我的编译命令:
gcc -lm -o wtf_sqrt wtf_sqrt.c
这是返回的错误:
/tmp/ccgQN7y7.o: In function `main':
wtf_sqrt.c:(.text+0x1c): undefined reference to `sqrt'
collect2: error: ld returned 1 exit status
我在Ubuntu 18.04 LTS上使用gcc
版本7.5.0。 libc6-dev
已安装(证明是,sqrt
如我在main
的第一行中一样使用时有效)。该代码是用gedit
编写的,因此使用空白字符应该不会有问题。不知道我还能给你什么其他信息...
在这一点上,我真的怀疑这是我的配置/发行版出现问题,但我需要一些外部建议。
解决方法
正如Araraer,Weather Vane和Tom Karzes用户的评论所建议的那样,问题在于-lm
在编译命令中的位置。我错误地认为,首先提供它是正确的方法,然后链接器可能知道在哪里找到该函数,但是相反,我应该最后提供它,以便链接器已经知道我需要程序中的sqrt
。实际上,不仅-l
选项的顺序很重要,而且(要)编译的文件的顺序也很重要。所以正确的命令是:
gcc -o wtf_sqrt wtf_sqrt.c -lm
如用户Weather Vane所解释的,由于优化,对sqrt
的第一次调用很可能被替换或删除,因此不会产生错误。
这个问题实际上有两个部分,每个部分都是先前问题的重复。
sqrt
不会在使用常量参数进行调用时引起链接错误的事实是,编译器会在编译期间对其进行评估,如回答here,here和{{3 }}。
即使在链接中包含-lm
也会获得链接错误的事实是,-lm
必须在使用数学库的模块之后列出,如here,{ {3}},here和here。
问题可能出在#mercadeoucab .p-menuitem{
float: right !important;
}
接受的参数中。这是sqrt()
标头中的函数:
math.h
如您所见,该函数采用的参数类型是双精度型。在您的第一个_Check_return_ _CRT_JIT_INTRINSIC double __cdecl sqrt(_In_ double _X);
调用中,您只需在括号内键入3即可传递值3-编译器可能将此3视为double并成功编译。但是在第二次调用中,您将参数sqrt()
设为x
(并且不会将其转换为int
)。由于C不支持函数重载,因此编译器找不到带有double
参数的sqrt
函数,并且会弹出错误。将int
转换为double可以解决此问题:
x