我在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()
都来自<math.h>
?
那么为什么不要floor()
和ceil()
抛出编译错误,而pow()
会抛出-lm
标记?
答案 0 :(得分:4)
从技术上讲,所有这些都需要-lm
才能正常工作。他们所有的man
页都包含以下内容:
与-lm链接。
但是你的不是编译器错误而是链接器错误,那就是你的程序编译得很好,但是如果你不使用-lm
就链接它就无法找到pow()
的实现但它实际上找到了ceil()
的实现。
这可能是因为在您的体系结构/配置中ceil()
是内联函数或内部函数,可能有一个简单的CPU指令来执行它,因此不需要库。但pow()
并非如此,您需要关联libm
。
更新:我刚刚做了一些实验,而-O0
-lm
所有功能都需要-O2
,pow()
只需要/usr/include/bits/mathinline.h
。修改我发现文件ceil()
的内联实现为floor()
和{{1}} ...
答案 1 :(得分:3)
编译器只抱怨pow()
而不是floor()
或ceil()
,因为它会生成floor()
和ceil()
的内联代码以及{{}的外部调用{1}}在链接时无法解析,因为您忘记了命令行上的pow()
库:m
代表与-lm
的链接。
顺便说一句,由于您不存储这些函数的返回值,因此编译器可能会使用其对这些纯函数的内在知识(在libm.a
中以某种方式传达)来完全删除调用。它可以为<math.h>
和ceil()
而不是floor()
执行此操作,这也可以解释观察到的行为。
实际上,可以在http://gcc.goldbolt.org/#上验证,没有命令行选项,您的代码编译为:
pow()
出于某种原因,编译器仅为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
和floor
生成内联代码,如所观察到的那样。
使用ceil
时会删除所有内容:
-O2
如果修改代码以将值存储到全局变量中,则会生成对main:
xorl %eax, %eax
ret
,floor()
和ceil()
的库调用而不进行优化,如果您编译,则由编译器计算值使用pow()
进行优化。
答案 2 :(得分:1)
您得到的错误是链接错误,而不是编译错误 Floor和ceil可能位于其他库中,通常编译器不需要诊断缺少的标头或库。