使用sqrt函数C,gcc时的链接器问题

问题描述

当我尝试编译以下最小示例时,我遇到一个奇怪的问题。对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不会在使用常量参数进行调用时引起链接错误的事实是,编译器会在编译期间对其进行评估,如回答herehere和{{3 }}。

即使在链接中包含-lm也会获得链接错误的事实是,-lm必须在使用数学库的模块之后列出,如here,{ {3}},herehere

,

问题可能出在#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