gpt4 book ai didi

c - 编译/链接期间由 GCC 确定的符号值

转载 作者:行者123 更新时间:2023-12-04 04:55:35 24 4
gpt4 key购买 nike

为什么在下面的代码中“if (sqrt)”条件总是正确的?编译时,gcc 会发出这样的警告,

weak.c: In function âfâ:
weak.c:6: warning: the address of âsqrtâ, will always evaluate as âtrueâ

源代码,
#include <stdio.h>

extern double sqrt(double x); /* DECLARATION VERSION 1 */
/* extern double sqrt(double x) __attribute__ ((weak)); */ /* DECLARATION VERSION 2 */

void f() {
if (sqrt) {
printf("sqrt of 10 %f \n", sqrt(10.0));
}
else {
printf("sqrt not found \n");
}
}

int main (int arg, char **argv)
{
f();
return 0;
}

如果我注释掉行-“声明版本 1”并取消注释行-“声明版本 2”,我有一个具有以下行为的二进制文件。
  • 当二进制文件与 -lm 链接时,“if (sqrt)”为真。
  • 如果不是,则条件为假。我知道/认为对于一个弱符号,这里是“sqrt”函数,链接时它被初始化为 0。因此,当“sqrt”符号在其他地方(库)找不到它的定义时,“if (sqrt)”条件为假。

  • 但是,当我使用“声明版本 1”时,为什么“sqrt”总是非零?在“DECLARATION VERSION 1”中,“sqrt”不是弱符号,当然也不是强符号。实际上,当您使用“nm”命令时,您找不到“sqrt”符号。更重要的是,当我尝试打印“sqrt”的地址时,我得到一个编译错误。

    有人知道“sqrt”不为零的原因吗?

    提前致谢!

    由于我找不到合适的标题来描述我的问题,如果有的话,请建议一个更好的标题。

    我想我找到了原因:

    gcc 有一个用于优化目的的内置 sqrt() 函数。如果可能,gcc 将用其内置的 sqrt() 替换 libm 中 sqrt() 的调用, http://gcc.gnu.org/onlinedocs/gcc/Other-Builtins.html .编译时,如果未关闭内置函数且未给出 libm(-lm),gcc 将使用其内置版本的 sqrt(),它始终具有非零地址。 当我关闭内置时,我得到一个编译错误 ,
    $ gcc -fno-builtin weak.c
    weak.c: In function âfâ:
    weak.c:9: warning: the address of âsqrtâ, will always evaluate as âtrueâ
    /tmp/cc84fwK9.o: In function `f':
    weak.c:(.text+0x11): undefined reference to `sqrt'
    weak.c:(.text+0x29): undefined reference to `sqrt'
    collect2: ld returned 1 exit status

    最佳答案

    在这两种情况下sqrt()是一个函数。对于 decl ver 1,在 if 语句中:

    if (sqrt)
    sqrt解析为该函数的地址,该地址在编译时已知(无论如何不能为零)。因为在 C 中,任何非零都为真,if 语句的条件,函数的地址,总是计算为真 :)

    当您使用 __attribute__ ((weak)) ,编译器允许你“检查”一个函数是否存在。如果不是,则仍会创建符号,但将其设置为 NULL。因此,当您将其设为“弱”链接函数时,符号 sqrt可能是 null (错误的)。

    From wikipedia ...

    In computing, a weak symbol is a symbol definition in an object file or dynamic library that may be overridden by other symbol definitions. Its value will be zero if no definition is found by the loader.



    总而言之,在 decl 版本 1 中,链接器必须找到函数 sqrt在编译时并将函数的地址绑定(bind)到该符号。因此符号不能为空。

    在 decl 版本 2 中,链接器不需要查找 sqrt .如果是, sqrt将解析到函数地址,但如果找不到函数,它将将该符号设置为 null .即,弱符号允许您定义不需要在链接时解析的符号......

    也来自 GNU Compiler Function Attributes :

    The weak attribute causes the declaration to be emitted as a weak symbol rather than a global. This is primarily useful in defining library functions which can be overridden in user code, though it can also be used with non-function declarations. Weak symbols are supported for ELF targets, and also for a.out targets when using the GNU assembler and linker.



    这不仅允许您检查函数是否存在,而且如上所述,它允许您覆盖函数。见 Understand Weak Symbols by Examples一个简洁的小例子和一些有用的引用资料(特别好 - GCC Weak Symbols - 给出了弱函数符号被强函数符号覆盖的例子)。

    关于c - 编译/链接期间由 GCC 确定的符号值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16787466/

    24 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com