数学库中的文字常量与变量 [英] literal constant vs variable in math library

查看:14
本文介绍了数学库中的文字常量与变量的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

所以,我知道在 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆