链接多个C源文件
我在GentooLinux上安装了GCC4.4.5。我可以使用gcc main.c-o main编译和链接这样的程序,并且命令./main正确返回结果链接多个C源文件,c,linker,gentoo,gcc4,C,Linker,Gentoo,Gcc4,我在GentooLinux上安装了GCC4.4.5。我可以使用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; } 那么,为什么在后一种情况下
[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;
}
那么,为什么在后一种情况下会出现令人讨厌的错误“未定义引用”?我知道通过添加一个库-lm可以消除错误,但是,我只想知道为什么gcc会在后一种情况下抛出错误 如果您先将main.c编译成main.o,然后将calc.c编译成calc.o,然后将它们链接起来,这样做有效吗?这通常是我所期望的(链接对象文件,而不是试图在一个命令行上编译多个C文件)。我的猜测是,GCC将
ceil(2.5)
优化为常数,而ceil(n)
不是常数,因为编译calc.C
时不知道n
,它需要引用函数。您可以通过查看程序集输出(gcc-S
)来确认这一点
更新:以下是x86上的GCC4.2.1为我提供的与第一个示例类似的内容:
.LC1:
.string "%f\n"
// [snip]
main:
// [snip]
fldl .LC0
fstpl 4(%esp)
movl $.LC1, (%esp)
call printf
// [snip]
.LC0:
.long 0
.long 1074266112
这里我们看到使用double
常量调用printf
现在,如果我做一些类似于第二个例子的事情:
myceil:
// [snip]
fldl -8(%ebp)
fstpl (%esp)
call ceil
// [snip]
在这里,我们看到正在引用ceil
所以是的。我想说,您的调用正在优化为一个常量,在这个常量中,没有
-lm
gcc有一个列表,而ceil
就是其中之一。在我的OSX版本中,gcc在两种情况下都使用内置的ceil
,因此-lm
不是必需的。显然,Gentoo编译器的行为不同,在某些情况下只使用内置的ceil
。如果您尝试使用-fno-builtin
编译,那么您必须对两种编译都使用-lm
。此错误不会出现在osx或RHEL 6中…@Foo,最近我在Vmware workstation 7.0.0上安装了RHEL-workstation-6.0-i386-dvd.iso,但是错误仍然存在。哦,我使用的是x64服务器版本谢谢你的回复。我使用了以下命令gcc-c calc.c
gcc-c main1.c
和gcc-o main1 calc.o main1.o
,但仍然出现相同的错误。您能告诉我如何具体使用gcc-S
,或者一些教程吗?谢谢。示例用法:gcc-sfoo.c
。这将输出一个名为foo.s
的文件。当然,了解一些平台的汇编语言也会对您有很大帮助。非常感谢。问题正是你说的。当我将ceil(2.5)
替换为ceil(x)
时,x的值为2.5,引用错误就会发生,就像我的后一种情况一样。如果你喜欢这类事情(嘿,谁不喜欢这类事情?),那么使用-fno-builtin检查可能会很有趣。谢谢@mu。当我在main.c-o main中使用gcc-fnobuilt时,会发生引用错误。似乎在我的gentoo中,内置函数只接受常量参数,例如,在我以前的例子中是2.5。@machinarium:这很酷,我认为它也经过了优化,但我想我还是要提到内置函数,因为它们可能会导致一些混乱的行为。可能是多文件问题,也可能是编译器配置中的问题。
.LC1:
.string "%f\n"
// [snip]
main:
// [snip]
fldl .LC0
fstpl 4(%esp)
movl $.LC1, (%esp)
call printf
// [snip]
.LC0:
.long 0
.long 1074266112
myceil:
// [snip]
fldl -8(%ebp)
fstpl (%esp)
call ceil
// [snip]