Linking multiple C source files
I'm on gentoo linux with GCC 4.4.5 installed. I can compile and link such program without any errors using gcc main.c -o main, and the command ./main returns result correctly.
[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;
}
But when I put the invokation of ceil into another source file, the problem occurs.
[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;
}
Using the command gcc calc.c main1.c -o main1, such error occurs:
/tmp/cc6GhJvZ.o: In function `myceil':
calc.c:(.text+0x19): undefined reference to `ceil'
collect2: ld returned 1 exit status
So why did the annoying error "undefined references" happen in the latter case? And I know the error could be eliminated by adding an library -lm, however, I just want to know why gcc will throw the error in the latter case.
My guess is that GCC optimizes ceil(2.5)
to a constant, whereas ceil(n)
is not constant because n
is not known when compiling calc.c
, and it needs to reference the function. You can confirm this by looking at the assembly output (gcc -S
).
Update: Here's what gcc 4.2.1 on x86 gave me for something similar to your first example:
.LC1:
.string "%f\n"
// [snip]
main:
// [snip]
fldl .LC0
fstpl 4(%esp)
movl $.LC1, (%esp)
call printf
// [snip]
.LC0:
.long 0
.long 1074266112
Here we see printf
being called with a double
constant.
Now if I do something similar to your second example:
myceil:
// [snip]
fldl -8(%ebp)
fstpl (%esp)
call ceil
// [snip]
Here we see ceil
being referenced.
So yeah. I'd say your call is being optimized to a constant in the one that works without -lm
.
gcc has a list of built-in functions and ceil
is one of them. On my version of OSX, gcc uses the built-in ceil
in both of your cases so -lm
is not necessary. Apparently your Gentoo compiler behaves differently and only uses the built-in ceil
in some cases. If you try compiling with -fno-builtin
then you'll have to use -lm
for both of your compilations.
Does it work if you first compile main.c to main.o and calc.c to calc.o, then link those? That's normally what I would expect (linking object files rather than trying to compile multiple C files on a single command line).
精彩评论