我们不确定外部模块是否提供一个函数func,但是我们不得不用这个函数。
一、问题声明
extern int func(void); //声明函数,告诉编译器不要管
...................int a = func(); //使用函数...................
这会导致2个结果:
1:外部存在这个函数func,并且EXPORT_SYMBOL(func),那么在我自己的模块使用这个函数func,正确。
2:外部其实不存在这个函数,那么我们使用func,程序直接崩溃。
二、如何解决
所以这个时候,__attribute__((weak)) 派上了用场。
在自己的模块中定义:
int __attribute__((weak)) func(......)
{
return 0;
}
将本模块的func转成弱符号类型,如果遇到强符号类型(即外部模块定义了func),那么我们在本模块执行的func将会是外部模块定义的func。类似于c++中的重载
如果外部模块没有定义,那么,将会调用这个弱符号,也就是在本地定义的func,直接返回了一个1(返回值视具体情况而定)
相当于增加了一个默认函数。
原理:
注: 连接器发现同时存在弱符号和强符号,有限选择强符号,如果发现不存在强符号,只存在弱符号,则选择弱符号。如果都不存在:静态链接,恭喜,编译时报错,动态链接:对不起,系统无法启动。
weak属性只会在静态库(.o .a )中生效,动态库(.so)中不会生效。
举个例子:
strong.c //生成libstrong.so#include <stdio.h>
void real_func()
{printf("int real func\n");
}weak.c //生成libweak.so#include <stdio.h>
void real_func() __attribute__((weak));
void real_func()
{printf("fake func\n");
}main.c //#include <stdio.h>
extern void real_func();
void main()
{real_func();
}
如果
gcc main.c -lstrong -lweak
那么输出结果"real func"。
如果
gcc main.c -lweak -lstrong
那么输出结果为"fake func"。
可见,对于动态库,weak属性毫无作用,且main中调用哪个real_func(),取决于顺序。
如果将strong.c 和 weak.c编译成.a或者.o
gcc main.c strong.o weak.o
或者
gcc main.c weak.o strong.o
那么输出结果都是"real func"。
所以,如果在so中使用weak属性,那么任何不符合预期的情况,都是可能出现的。
官方解释:
https://sourceware.org/bugzilla/show_bug.cgi?id=3946