常量VS在数学库变量 [英] literal constant vs variable in math library
问题描述
所以,我知道,在 C
您需要将code链接到数学库,的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.
考虑以下code:
#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;
}
如果变量
定义,则需要对的libm
链接,你通常会期望;否则,你得到通常的main.c :(文字+ 0x29):未定义引用开方
链接表明编译器无法找到该函数的定义错误开方
。我很惊讶地看到,如果我评论#定义变量
中,code运行良好,其结果是正确的!
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
使用变量的时候,但我并不需要做的,所以当使用文字常量?编译器如何找到的开方
时,库不链接的定义是什么?我使用的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\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
您可以看到,它发出的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:用文字
.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
有对没有调用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
$
这篇关于常量VS在数学库变量的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!