// fun.c
#include <stdio.h>
void func()
{
printf("func\n");
}
// mian.c
#include <stdio.h>
void func()
{
printf("func\n");
}
int main(void)
{
func();
return 0;
}
gcc main.c fun.c
/tmp/ccxn0naT.o: In function `func':
main.c:(.text+0x0): multiple definition of `func'
/tmp/ccgZJUf1.o:fun.c:(.text+0x0): first defined here
collect2: error: ld returned 1 exit status
平常会遇到一种错误就是重定义的问题,这个问题本质上是强弱符号的问题。
强符号和弱符号
编译器默认函数和初始化了的全局变量为强符号,未初始化的全局变量为弱符号。
int num1; // 未初始化全局变量,弱符号
int num2 = 10; // 已初始化全局变量,强符号
void func() // 函数强符号
{
printf("func\n");
}
但是我们也可以用__attribute__((weak))
来修饰,将一个强符号转换为弱符号。
__attribute__((weak)) int num2 = 2222; // 使用标识修饰的弱符号
- 当强弱符号出现同名时,链接器怎么选择?
- 强符号不允许重复
- 有一个强符号和多个弱符号,使用强符号
#include <stdio.h> int num1; // 未初始化全局变量,弱符号 int num1 = 10; // 已初始化全局变量,强符号 int main() { printf("func: %d\n", num1); // 输出10 }
- 多个弱符号,随意选择一个
利用强弱符号规则制作插件
实现一个类似插件的功能:
- 当没有插件时,使用默认行为
- 链接了插件时,使用插件的功能
// main.c
#include <stdio.h>
__attribute__((weak)) void foo();
void test()
{
// 如果是强符号,说明链接了外部插件,使用外部定义
if (foo)
{
foo();
}
else
// 弱符号,走默认逻辑
{
printf("foo\n");
}
}
int main()
{
test();
}
制作插件库:
// plugin.c
#include<stdio.h>
void foo()
{
printf("plugin foo\n");
}
$ gcc -c plugin.c -o plugin.o
$ ar -rcs libplugin.a plugin.o
链接插件库:
# gcc -o main main.c -L. -Wl,--whole-archive -lplugin -Wl,--no-whole-archive
# ./main
plugin foo
这里需要加上-Wl,--whole-archive
,该选项会将插件库中所有符号都链接进来,若非如此,在main.o中已经有了foo
符号,将不会链接进来,而在此之后,又要将该选项恢复。最终我们可以通过nm命令看到foo
符号已经不再是W了。
网友评论