数学库中的文字常量与变量 [英] literal constant vs variable in math library
问题描述
所以,我知道在 C
中您需要将代码链接到数学库 libm
才能使用它的功能.今天,当我试图向朋友演示这一点并解释为什么需要这样做时,我遇到了以下我不明白的情况.
So, I know that in C
you need to link the code to the math library, libm
, to be able to use its functions. Today, while I was trying to demonstrate this to a friend, and explain why you need to do this, I came across the following situation that I do not understand.
考虑以下代码:
#include <math.h>
#include <stdio.h>
/* #define VARIABLE */
int main(void)
{
#ifdef VARIABLE
double a = 2.0;
double b = sqrt(a);
printf("b = %lf
",b);
#else
double b = sqrt(2.0);
printf("b = %lf
",b);
#endif
return 0;
}
如果定义了VARIABLE
,你需要像通常期望的那样链接到libm
;否则你会得到通常的 main.c:(.text+0x29): undefined reference to sqrt
链接错误,表明编译器找不到函数 sqrt
的定义.我很惊讶地发现,如果我注释 #define VARIABLE
,代码运行良好并且结果是正确的!
If VARIABLE
is defined, you need to link against libm
as you would normally expect; otherwise you get the usual main.c:(.text+0x29): undefined reference to sqrt
linking error indicating that the compiler cannot find the definition for the function sqrt
. I was surprised to see that if I comment #define VARIABLE
, the code runs fine and the result is correct!
为什么在使用变量时我需要链接到 libm
而在使用文字常量时我不需要这样做?库未链接时,编译器如何找到sqrt
的定义?我在linux下使用gcc 4.4.5
.
Why is it that I need to link to libm
when variables are used but I don't need to do so when literal constants are used? How does the compiler find the definition of sqrt
when the library is not linked? I'm using gcc 4.4.5
under linux.
推荐答案
正如大家所说,是的,它与 不断折叠.
As everyone mentions, yes it has to do with constant folding.
关闭优化,GCC 似乎只在使用 sqrt(2.0)
时才会这样做.这是证据:
With optimizations off, GCC only seems to do it when sqrt(2.0)
is used. Here's the evidence:
案例1:使用变量.
.file "main.c"
.section .rodata
.LC1:
.string "b = %lf
"
.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
您可以看到它发出了对 sqrt
函数的调用.所以如果你不链接数学库,你会得到一个链接器错误.
You can see that it emits a call to the sqrt
function. So you'll get a linker error if you don't link the math library.
案例 2: 使用 Literal.
Case 2: With the Literal.
.file "main.c"
.section .rodata
.LC1:
.string "b = %lf
"
.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
没有调用 sqrt
.因此没有链接器错误.
There's no call to sqrt
. Hence no linker error.
通过优化,GCC 将在这两种情况下进行持续传播.所以在这两种情况下都没有链接器错误.
With optimizations on, GCC will do constant propagation in both cases. So no linker error in either case.
$ 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
$
这篇关于数学库中的文字常量与变量的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!