Связывание нескольких исходных файлов C - PullRequest
4 голосов
/ 22 августа 2011

Я на Gentoo Linux с установленным GCC 4.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;
}

Но когда я помещаю вызов 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 выдаст ошибку в последнем случае.

Ответы [ 3 ]

5 голосов
/ 22 августа 2011

Я предполагаю, что GCC оптимизирует ceil(2.5) до константы, тогда как ceil(n) не является константой, поскольку n неизвестно при компиляции calc.c, и ему необходимо обратиться к функции. В этом можно убедиться, посмотрев выходные данные сборки (gcc -S).

Обновление: Вот что мне дал gcc 4.2.1 на x86 для чего-то похожего на ваш первый пример:

.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.

2 голосов
/ 22 августа 2011

gcc имеет список встроенных функций , и ceil является одной из них.В моей версии OSX gcc использует встроенный ceil в обоих ваших случаях, поэтому -lm не требуется.Очевидно, ваш компилятор Gentoo ведет себя по-другому и использует только встроенный ceil в некоторых случаях.Если вы попытаетесь скомпилировать с -fno-builtin, вам придется использовать -lm для обеих ваших компиляций.

0 голосов
/ 22 августа 2011

Работает ли это, если вы сначала скомпилируете main.c в main.o и calc.c в calc.o, а затем связываете их?Это обычно то, что я ожидал (связывая объектные файлы вместо того, чтобы пытаться скомпилировать несколько файлов C в одной командной строке).

...