4

我在安装了 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 会在后一种情况下抛出错误。

4

3 回答 3

5

我的猜测是 GCC 优化ceil(2.5)为一个常量,而ceil(n)不是常量,因为n在编译时不知道calc.c,它需要引用该函数。您可以通过查看程序集输出 ( gcc -S) 来确认这一点。

更新:这是 x86 上的 gcc 4.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

在这里,我们看到printf被一个double常量调用。

现在,如果我执行类似于您的第二个示例的操作:

myceil:
    // [snip]
    fldl    -8(%ebp)
    fstpl   (%esp)
    call    ceil
    // [snip]

在这里,我们看到ceil被引用。

是的。我会说你的电话正在被优化为一个常数,在没有-lm.

于 2011-08-22T05:58:42.313 回答
2

gcc 有一个内置函数列表,ceil它就是其中之一。在我的 OSX 版本上,gcc 在你的两种情况下都使用内置的,ceil所以-lm没有必要。ceil显然你的 Gentoo 编译器的行为不同,并且在某些情况下只使用内置的。如果您尝试编译,-fno-builtin那么您将不得不使用-lm您的两个编译。

于 2011-08-22T06:04:13.593 回答
0

如果您首先将 main.c 编译为 main.o 并将 calc.c 编译为 calc.o,然后将它们链接起来,它是否有效?这通常是我所期望的(链接目标文件而不是尝试在单个命令行上编译多个 C 文件)。

于 2011-08-22T05:57:31.067 回答