C语言 weak弱符号(GCC扩展)
__attribute__((weak))
是 GCC 和 Clang
提供的一个特性,用于声明一个符号为 "弱符号"(weak
symbol),在链接层面提供更多的灵活性。注意并不是 C
语言标准的一部分,MSVC并不支持,但是提供了一个类似的特性:#pragma weak
。
概述
编译器将一个符号(函数名,变量名)区分为强符号(strong
symbol)和弱符号(weak
symbol),通常绝大多数的符号都是强符号,重复出现会导致链接错误。在定义时使用
__attribute__((weak))
可以将其设置为弱符号,语法如下(在符号声明时不需要)
1 | <符号类型> __attribute__((weak)) <符号名称>; |
这可以使得它在链接过程中具有较低的优先级:
- 如果在链接过程中找到了同名的强符号和弱符号,弱符号会被强符号覆盖。
- 如果找到多个同名的强符号,会导致链接错误(link error)。
- 在没有找到强符号时:如果只有唯一的弱符号,那么这个弱符号会被使用;如果存在多个同名的弱符号,可能会使用其中一个版本,取决于具体实现,并且很可能和链接顺序有关,通常会使用第一个或最后一个版本。
因此使用弱符号可以在库中给函数提供一个默认实现,同时允许用户提供自己的实现(作为强符号,覆盖默认实现), 这可以让用户在不改变库代码的前提下,在不同平台或配置环境中使用不同的实现版本。
实例
假设我们在某个库中定义了一个函数
foo
,并且希望用户可以根据需求选择是否重定义它。
库的内容如下 1
2
3
4
5
void __attribute__((weak)) foo() {
printf("This is the default foo implementation.\n");
}
如果用户没有定义,就使用默认的 foo
实现
1
2
3
4
5
6
7
8
extern void foo();
int main() {
foo();
return 0;
}
否则使用用户定义的 foo
1
2
3
4
5
6
7
8
9
10
11
12
extern void foo();
void foo() {
printf("This is the user-defined foo implementation.\n");
}
int main() {
foo();
return 0;
}
编译为动态库后分别调用,就可以得到不同的结果 1
2gcc -fPIC -shared foo.c -o libfoo.so
gcc main.c -lfoo -L. -o main
使用静态库也是一样的,不影响这里的结果。