1.弱符号:
弱符号,这涉及到编译中符号的概念。在Linux开发环境中,有强符号和弱符号,符号简单来说就是函数、变量的名字,对于全局(非局部、非static)的函数和变量,能不能重名是有一定规矩的,强、弱符号就是针对这些全局函数和变量来说的。
符号类型 | 对象 |
强 | 函数名,赋初值的全局变量 |
弱 | 未初始化的全局变量 |
当代码中同时存在多个强或弱的全局变量时,要遵守如下规则
-
强符号只能定义一次,否则编译错误
-
强弱符号同时存在,以强符号为准
-
没有强符号,则从多个弱符号中任选一个,用
–fno-common
编译选项可以在这种情况下打出warning
弱符号的声明
弱符号的声明有两种方式
第一种,用__attribute__((weak))
修饰,例如
void __attribute__((weak)) func(void);
extern int __attribute__((weak)) var;
第二种,用#pragma weak
标记,例如
#pragma weak func
代码演示
main.c
这个文件中main
函数调用了2个声明为弱符号的函数,它们是weak0
和weak1
#include <stdio.h>
void __attribute__((weak)) weak0(void);
void __attribute__((weak)) weak1(void);
int main(int argc, char **argv){
if (weak0){
weak0();
}
else{
printf("weak0=%p\n", weak0);
}
if (weak1){
weak1();
}
else{
printf("weak1=%p\n", weak0);
}
return 0;
}
weak.c
这个文件中定义了2个函数(它们还是weak0
和weak1
),并强制声明为弱符号
#include <stdio.h>
#pragma weak weak0
void __attribute__((weak)) weak1(void);
static char *label = "weak";
void weak0(void){
printf("[%s]%s is called\n", label, __FUNCTION__);
}
void weak1(void){
printf("[%s]%s is called\n", label, __FUNCTION__);
}
strong.c
这个文件中重复定义(与上面重复)了两个函数,它们又是weak0
和weak1
#include <stdio.h>
static char *label = "strong";
void weak0(void){
printf("[%s]%s is called\n", label, __FUNCTION__);
}
void weak1(void){
printf("[%s]%s is called\n", label, __FUNCTION__);
}
编译与输出
编译main.c
当弱符号函数链接不成功,处于未定义状态时,其名字所代表的地址为nil
。
user@user-virtual-machine:~/weak symbol$ gcc main.c -o test && ./test
weak0=(nil)
weak1=(nil)
编译main.c+weak.c
弱符号链接成功时,可以被正常调用。
user@user-virtual-machine:~/weak symbol$ gcc main.c weak.c -o test && ./test
[weak]weak0 is called
[weak]weak1 is called
编译main.c+weak.c+strong.c
当强符号定义出现时,弱符号定义不起作用。
user@user-virtual-machine:~/weak symbol$ gcc main.c weak.c strong.c -o test && ./test
[strong]weak0 is called
[strong]weak1 is called