在Linux开发环境中,有强符号和弱符号,符号简单来说就是函数、变量的名字,对于全局(非局部、非static)的函数和变量,能不能重名是有一定规矩的,强、弱符号就是针对这些全局函数和变量来说的。
强符号与弱符号
在C语言中,函数和初始化的全局变量(包括显示初始化为0)是强符号,未初始化的全局变量是弱符号。其规则如下:
- 同名的强符号只能定义一次,否则编译错误。
- 同名的强弱符号同时存在时,以强符号为准。
- 多个弱符号相同时,则从多个弱符号中任选一个。
声明弱符号
弱符号的声明可采用两种方式:
- 使用
__attribute__((weak))
修饰:
void __attribute__((weak)) func(void)
or
__attribute__((weak)) void func(void)
or
void func(void)__attribute__((weak))
- 使用
#pragma weak
修饰:
#pragma weak func
举个例子
main.c
#include <stdio.h>
void __attribute__((weak)) func(void)
{
printf("Can't find the define of %s!\n", __FUNCTION__);
}
int main(int argc, char **argv)
{
func();
return 0;
}
编译输出:
$ gcc main.c -o test && ./test
Can't find the define of func!
Note:对于上述函数的声明,还可以这样写:
void __attribute__((weak)) func(void); void func(void) { printf("Can't find the define of %s!\n", __FUNCTION__); }
还可以这样写:
void func(void)__attribute__((weak)); void func(void) { printf("Can't find the define of %s!\n", __FUNCTION__); }
但是下面的写法就是导致编译失败:
void func(void)__attribute__((weak)) { printf("Can't find the define of %s!\n", __FUNCTION__); }
func.c
#include <stdio.h>
void func(void)
{
printf("I‘m the define of %s!\n", __FUNCTION__);
}
编译输出:
$ gcc main.c func.c -o test && ./test
I'm the define of func!
结论:同名函数的强符号和弱符号同时存在时,以强符号为准,弱符号失去作用。因此在实际开发中,若函数func
还未ready,在调用func
函数的主函数中对其声明为__attribute__((weak))
后可以使主函数编译通过,否则主函数因无法link函数func
而编译失败。
__weak的含义
有时候在代码中可以看到会用到__weak
,其实__weak
是一个宏定义,在Linux代码中可以见其定义在include/linux/compiler_attributes.h
中:
#define __weak __attribute__((weak))
它常用于函数和变量的声明和函数的定义,是GNU compiler的扩展,被ARM compiler支持,可以将一个函数声明为weak,当没有其他同名函数声明时调用weak,有其他同名函数时调用其他同名函数。
网友评论