所以,我知道C你需要将代码链接到数学库libm,以便能够使用它的功能.今天,当我试图向朋友证明这一点,并解释为什么你需要这样做时,我遇到了以下我不理解的情况.
请考虑以下代码:
#include <math.h>
#include <stdio.h>
/* #define VARIABLE */
int main(void)
{
#ifdef VARIABLE
double a = 2.0;
double b = sqrt(a);
printf("b = %lf\n",b);
#else
double b = sqrt(2.0);
printf("b = %lf\n",b);
#endif
return 0;
}
Run Code Online (Sandbox Code Playgroud)
如果VARIABLE已定义,则需要libm按照通常的预期进行链接; 否则你得到通常的main.c:(.text+0x29): undefined reference to sqrt链接错误,表明编译器找不到该函数的定义sqrt.我很惊讶地看到,如果我评论#define VARIABLE,代码运行正常,结果是正确的!
为什么libm在使用变量时我需要链接到但是在使用文字常量时我不需要这样做?编译器如何找到sqrt未链接库的定义?我gcc 4.4.5在linux下使用.
关闭优化后sqrt(2.0),GCC 似乎仅在使用时才执行此操作。证据如下:
情况1:有变量。
.file "main.c"
.section .rodata
.LC1:
.string "b = %lf\n"
.text
.globl main
.type main, @function
main:
pushl %ebp
movl %esp, %ebp
andl $-16, %esp
subl $32, %esp
fldl .LC0
fstpl 24(%esp)
fldl 24(%esp)
fsqrt
fucom %st(0)
fnstsw %ax
sahf
jp .L5
je .L2
fstp %st(0)
jmp .L4
.L5:
fstp %st(0)
.L4:
fldl 24(%esp)
fstpl (%esp)
call sqrt
.L2:
fstpl 16(%esp)
movl $.LC1, %eax
fldl 16(%esp)
fstpl 4(%esp)
movl %eax, (%esp)
call printf
movl $0, %eax
leave
ret
.size main, .-main
.section .rodata
.align 8
.LC0:
.long 0
.long 1073741824
.ident "GCC: (Ubuntu 4.4.3-4ubuntu5) 4.4.3"
.section .note.GNU-stack,"",@progbits
Run Code Online (Sandbox Code Playgroud)
您可以看到它发出了对该sqrt函数的调用。因此,如果不链接数学库,则会出现链接器错误。
情况 2:使用文字。
.file "main.c"
.section .rodata
.LC1:
.string "b = %lf\n"
.text
.globl main
.type main, @function
main:
pushl %ebp
movl %esp, %ebp
andl $-16, %esp
subl $32, %esp
fldl .LC0
fstpl 24(%esp)
movl $.LC1, %eax
fldl 24(%esp)
fstpl 4(%esp)
movl %eax, (%esp)
call printf
movl $0, %eax
leave
ret
.size main, .-main
.section .rodata
.align 8
.LC0:
.long 1719614413
.long 1073127582
.ident "GCC: (Ubuntu 4.4.3-4ubuntu5) 4.4.3"
.section .note.GNU-stack,"",@progbits
Run Code Online (Sandbox Code Playgroud)
没有人打电话给sqrt。因此没有链接器错误。
通过对 的优化,GCC 将在这两种情况下进行恒定传播。所以在任何一种情况下都没有链接器错误。
$ gcc main.c -save-temps
main.o: In function `main':
main.c:(.text+0x30): undefined reference to `sqrt'
collect2: ld returned 1 exit status
$ gcc main.c -save-temps -O2
$
Run Code Online (Sandbox Code Playgroud)