为什么在下面的代码“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”,我有一个具有以下行为的二进制文件。
但是,当我使用“DECLARATION VERSION 1”时,为什么“sqrt”始终为零?在“宣言版本1”中,“sqrt”不是弱势符号,当然也不是强烈的符号。实际上,当您使用“nm”命令时,您找不到“sqrt”符号。更重要的是,当我尝试打印出“sqrt”的地址时,我收到了编译错误。
有人知道“sqrt”为零的原因吗?
提前致谢!
由于我找不到合适的标题来描述我的问题,如果有的话,请建议一个更好的标题。
我想我找到了原因:
gcc有一个内置的sqrt()函数用于优化目的。如果可能,gcc将用其内置的sqrt(),http://gcc.gnu.org/onlinedocs/gcc/Other-Builtins.html替换libm中的sqrt()调用。编译时,如果内置函数未关闭且未给出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
答案 0 :(得分:3)
在这两种情况下sqrt()
都是一个函数。对于decl ver 1,在if语句中:
if (sqrt)
sqrt
解析为该函数的地址,这在编译时已知(并且无论如何都不能为零)。因为在C中,任何非零都为真,if语句的条件,函数的地址,总是求值为true:)
使用__attribute__ ((weak))
时,编译器允许您“检查”函数是否存在。如果没有,则仍然创建符号,但设置为NULL。因此,当您将其设为“弱”链接函数时,符号sqrt
可能为null
(false)。
From wikipedia ...
在计算中,弱符号是目标文件中的符号定义 或者可以被其他符号定义覆盖的动态库。 如果加载器没有找到定义,它的值将为零。
总而言之,在decl版本1中,链接器必须在编译时找到函数sqrt
,并将函数的地址绑定到该符号。因此,符号不能为空。
在decl版本2中,链接器不需要找到sqrt
。如果是,sqrt
将解析为函数地址,但如果找不到该函数,则会将该符号设置为null
。即,弱符号允许您定义在链接时不需要解析的符号...
同样来自GNU Compiler Function Attributes:
weak属性导致声明以弱的形式发出 符号而不是全球。这主要用于定义 可以在用户代码中覆盖的库函数 也可以与非函数声明一起使用。弱符号是 支持ELF目标,也支持a.out目标使用时 GNU汇编器和链接器。
这不仅可以让您检查函数是否存在,而且如上所述,它允许您覆盖函数。请参阅Understand Weak Symbols by Examples以获得一个简洁的小例子和一些有用的参考资料(特别好 - GCC Weak Symbols - 给出弱函数符号被强函数符号覆盖的示例)。