我在安装了GCC 4.4.5的gentoo linux上。我可以使用 gcc main.c -o main 编译和链接这样的程序而没有任何错误,并且命令 ./ main 正确返回结果。
[main.c]
#include <math.h>
#include <stdio.h>
int main(void)
{
double c = ceil(2.5);
printf("The ceil of 2.5 is %f\n", c);
return 0;
}
但是当我把 ceil 的调用放到另一个源文件中时,会出现问题。
[calc.h]
#ifndef _CALC_H_
#define _CALC_H_
double myceil(double n);
#endif
[calc.c]
#include <math.h>
#include "calc.h"
double myceil(double n)
{
return ceil(n);
}
[main1.c]
#include <stdio.h>
#include "calc.h"
int main(void)
{
double c = myceil(2.5);
printf("The ceil of 2.5 is %f\n", c);
return 0;
}
使用命令 gcc calc.c main1.c -o main1 ,会发生此类错误:
/tmp/cc6GhJvZ.o: In function `myceil':
calc.c:(.text+0x19): undefined reference to `ceil'
collect2: ld returned 1 exit status
那么为什么在后一种情况下会发生恼人的错误“未定义的引用”呢?我知道可以通过添加库 -lm 来消除错误,但是,我只是想知道为什么gcc会在后一种情况下抛出错误。
答案 0 :(得分:5)
我的猜测是GCC将ceil(2.5)
优化为常量,而ceil(n)
不是常量,因为编译n
时calc.c
未知,并且需要引用gcc -S
功能。您可以通过查看汇编输出(.LC1:
.string "%f\n"
// [snip]
main:
// [snip]
fldl .LC0
fstpl 4(%esp)
movl $.LC1, (%esp)
call printf
// [snip]
.LC0:
.long 0
.long 1074266112
)确认这一点。
更新:以下是x86上的gcc 4.2.1给出了类似于你的第一个例子的内容:
printf
我们在此处看到double
被myceil:
// [snip]
fldl -8(%ebp)
fstpl (%esp)
call ceil
// [snip]
常量调用。
现在,如果我做了类似于你的第二个例子的事情:
ceil
我们在此处看到-lm
被引用。
所以是的。我会说你的电话被优化为一个在没有{{1}}的情况下工作的常量。
答案 1 :(得分:2)
gcc列有built-in functions,ceil
就是其中之一。在我的OSX版本中,gcc在两种情况下都使用内置ceil
,因此不需要-lm
。显然,您的Gentoo编译器的行为有所不同,在某些情况下仅使用内置的ceil
。如果您尝试使用-fno-builtin
进行编译,那么您必须使用-lm
进行两次编辑。
答案 2 :(得分:0)
如果你首先将main.c编译为main.o并将calc.c编译为calc.o,然后将它们链接起来,它是否有用?这通常是我所期望的(链接目标文件而不是尝试在单个命令行上编译多个C文件)。