【问题标题】:Error linking code with `floor();`, `ceil();` and `pow();` [duplicate]将代码与 `floor();`、`ceil();` 和 `pow();` 链接时出错 [重复]
【发布时间】:2016-12-27 15:38:24
【问题描述】:

我在 GNU/Linux Debian 8.5 下编码

我有一个简单的程序。

如果我用gcc prog.c 编译它就可以了!

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

int main(int argc, char const *argv[]) {

    float _f = 3.1415f;

    floor(_f);
    ceil(_f);

    return 0;
}

如果我添加pow(),它会说找不到pow,我需要添加gcc prog.c -lm 才能正确。

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

int main(int argc, char const *argv[]) {

    float _f = 3.1415f;

    floor(_f);
    ceil(_f);
    pow(_f, 2);

    return 0;
}

如果我是对的,pow()ceil()floor() 都来自&lt;math.h&gt;

那么为什么floor()ceil() 不抛出编译错误,而pow() 不抛出-lm 标志呢?

【问题讨论】:

标签: c linker-errors flags undefined-reference math.h


【解决方案1】:

从技术上讲,它们都需要-lm 才能工作。他们所有的man 页面都包含这一行:

与 -lm 链接。

但是您的不是编译器错误而是链接器错误,即您的程序编译正常,但是在链接时如果您不使用-lm,则无法找到pow()的实现,但它实际上找到了ceil()的实现。

这可能是因为在您的架构/配置中ceil() 是一个内联或内在函数,也许有一个简单的 CPU 指令可以做到这一点,所以不需要库。但是pow() 不是,所以你需要链接libm

更新:我刚刚做了一些实验,对于-O0,您的所有功能都需要-lm,但对于-O2,只有pow()。修补一下,我找到了 /usr/include/bits/mathinline.h 文件,其中包含 ceil()floor() 的内联实现...

【讨论】:

  • "你的不是编译器错误,而是链接器错误" - 你怎么知道?
  • @melpomene:因为-lm 是一个链接器选项。如果 OP 包含了实际确切的消息,undefined reference to 'pow' 那么它会更明显,因为未定义的引用是链接器的东西。
  • @ch3ll0v3k:请注意,&lt;math.h&gt; 是标头,而不是库。标头声明了一些可从库中获得的功能,当与库链接时,一切都会好起来的。在第一个示例中,编译器可以计算结果。它不计算pow() 的结果(这有点令人惊讶,但完全是它的特权),因此它需要在链接时找到库。许多函数都在标准 C 库中;数学函数不在 Linux 上,符合古老的 Unix 历史(但 Mac OS X 不需要-lm)。
【解决方案2】:

编译器只抱怨pow() 而不是floor()ceil(),这可能是因为它为floor()ceil() 生成内联代码以及对pow() 的外部调用,这在链接时无法解决,因为您忘记了命令行中的 m 库:-lm 代表 libm.a 的链接

顺便说一句,由于您不存储这些函数的返回值,编译器可能会使用其对这些纯函数的内在知识(在&lt;math.h&gt; 中以某种方式传达)来完全删除调用。它可能对ceil()floor() 这样做,而不是对pow(),这也可以解释观察到的行为。

确实,可以在http://gcc.goldbolt.org/# 上验证,没有命令行选项,您的代码编译为:

main:
        pushq   %rbp
        movq    %rsp, %rbp
        subq    $32, %rsp
        movl    %edi, -20(%rbp)
        movq    %rsi, -32(%rbp)
        movss   .LC0(%rip), %xmm0
        movss   %xmm0, -4(%rbp)
        cvtss2sd        -4(%rbp), %xmm0
        movsd   .LC1(%rip), %xmm1
        call    pow
        movl    $0, %eax
        leave
        ret
.LC0:
        .long   1078529622
.LC1:
        .long   0
        .long   1073741824

由于某种原因,编译器只为floorceil 生成内联代码,正如观察到的那样。

使用-O2 时,它会删除所有内容:

main:
        xorl    %eax, %eax
        ret

如果您修改代码以将值存储到全局变量中,则对 floor()ceil()pow() 的库调用将在没有优化的情况下生成,并且如果您使用 -O2 进行优化,则编译器会计算这些值。

【讨论】:

  • 我确实包括 ,duuuh
  • @ch3ll0v3k:您没有发布#include &lt;math.h&gt;... 我猜不出您的文件中有什么,因此我使用了条件 If you do not include...我>
  • 我说如果我使用 floor();它编译。
  • @ch3ll0v3k:一些编译器默认不发出警告。它编译的事实并不能证明太多。
【解决方案3】:

您得到的错误是链接错误,而不是编译错误。
floor 和 ceil 可能在其他库中,通常不需要编译器来诊断丢失的头文件或库。

【讨论】:

  • "你得到的错误是链接错误,而不是编译错误" - 你怎么知道?
猜你喜欢
  • 2017-02-19
  • 1970-01-01
  • 2019-02-24
  • 1970-01-01
  • 1970-01-01
  • 2018-12-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多