【问题标题】:Linker problem when using sqrt function (C, gcc) [duplicate]使用 sqrt 函数(C,gcc)时的链接器问题 [重复]
【发布时间】:2021-02-24 08:56:09
【问题描述】:

当我尝试编译以下最小示例时,我遇到了一个奇怪的问题。第一次调用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写的,所以应该没有空白字符的问题。不知道我还能给你什么其他信息……

在这一点上,我真的怀疑这是我的配置/分发的问题,但我想要一些外部建议。

【问题讨论】:

  • 在 cent os 7 上运行良好,可能是您使用的操作系统没有安装它
  • 参数的顺序可能很重要。尝试将 -lm 移动到所有源/目标文件之后。
  • sqrt(3); 可以被编译器替换为 3 的平方根。或者优化出来,因为它什么都不做。
  • 库在它们出现在命令行的地方被搜索,所以如果sqrt没有被它前面的文件引用,它可能不会被包括在内。将-lm 选项移到最后,它应该可以工作。

标签: c gcc linker-errors


【解决方案1】:

这个问题实际上有两个部分,每个部分都是前面问题的重复。

sqrt 在使用常量参数调用时不会导致链接错误的事实是编译器会在编译期间对其进行评估,如回答 hereherehere

即使-lm 包含在链接中也会出现链接错误,因为-lm 必须列在使用数学库的模块之后,如回答herehereherehere

【讨论】:

    【解决方案2】:

    正如用户 aragaer、Weather Vane 和 Tom Karzes 在 cmets 中所建议的,问题出在编译命令中 -lm 的位置。我错误地认为首先提供它是正确的方法,因为那时链接器可能知道在哪里可以找到该函数,但我应该最后提供它,以便链接器已经知道我需要来自我的程序的sqrt。事实上,不仅-l 选项的顺序很重要,而且文件(要)编译的顺序也很重要。所以正确的命令是:

    gcc -o wtf_sqrt wtf_sqrt.c -lm
    

    正如用户 Weather Vane 所解释的,对 sqrt 的第一次调用可能由于优化而被替换或删除,因此不会产生错误。

    【讨论】:

      【解决方案3】:

      问题可能出在sqrt() 的论点上。这是math.h header 中的函数:

      _Check_return_ _CRT_JIT_INTRINSIC double __cdecl sqrt(_In_ double _X);
      

      如您所见,函数采用的参数类型是双精度型。在您的第一个 sqrt() 调用中,您只需在括号内键入 3 的值即可传递它 - 编译器可能将此 3 视为双精度并成功编译。但是在第二次调用中,您将x 作为参数传递,这是一个int(并且您不会将其转换为double)。由于 C 不支持函数重载,因此编译器找不到带有 int 参数的 sqrt 函数并弹出错误。将 x 转换为 double 应该可以解决问题:

      sqrt((double)x);
      

      【讨论】:

      • 我在这里粘贴的函数来自windows header,你使用的是Ubuntu。但即使在 Linux 中,“math.h”标头也显示“sqrt”采用 double 作为参数
      • 感谢您的建议。但是,我忘了提到我已经尝试将 x 转换为 double 甚至更改变量的类型,但它没有任何改变。另外,我在网上找到了很多在int 上使用sqrt 的例子,所以我想这不是问题。
      • As C doesn't support function overloading, the compiler can't find the sqrt 没有意义 - C 有隐式转换,这发生在调用函数时。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2010-09-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-12-11
      • 1970-01-01
      相关资源
      最近更新 更多