将代码与“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
由于某些原因,编译器只为 floor
和 ceil
生成内联代码,如观察到的那样。
虽然使用 -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.h
与 ceil()
和 floor()
...
的内联实现
我在 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
由于某些原因,编译器只为 floor
和 ceil
生成内联代码,如观察到的那样。
虽然使用 -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.h
与 ceil()
和 floor()
...