链接多个C源文件

链接多个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; } 那么,为什么在后一种情况下

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

那么,为什么在后一种情况下会出现令人讨厌的错误“未定义引用”?我知道通过添加一个库-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]