将代码与“floor();”、“ceil();”和“pow();”链接时出错

Error linking code with `floor();`, `ceil();` and `pow();`

我在 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;
}

Bud如果我加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()都来自<math.h>?

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

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

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

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

main:
        pushq   %rbp
        movq    %rsp, %rbp
        subq    , %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    [=10=], %eax
        leave
        ret
.LC0:
        .long   1078529622
.LC1:
        .long   0
        .long   1073741824

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

虽然使用 -O2 它会删除所有内容:

main:
        xorl    %eax, %eax
        ret

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

进行优化

您遇到的错误是链接错误,不是编译错误。
floor 和 ceil 可能在其他一些库中,通常不需要编译器来诊断缺少的头文件或库。

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

Link with -lm.

但是你的不是编译器错误而是 linker 错误,那是你的程序编译正常,但是当 linking 如果你不使用 -lm 它无法找到 pow() 的实现,但它实际上找到了 ceil().

的实现

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

更新:我刚刚做了一些实验,使用 -O0 你所有的函数都需要 -lm 但只有 -O2 pow()。修补我发现文件 /usr/include/bits/mathinline.hceil()floor()...

的内联实现