GCC弱符号的一个应用示例

194 阅读2分钟

这是我参与8月更文挑战的第23天,活动详情查看:8月更文挑战

GCC对C/C++做了很多扩展,很多基于Linux环境的开源项目都会使用。本文介绍一下弱符号的应用。
对于大型项目特别是兼容多种平台的项目来说,同一功能的实现会区别于不同平台,比如linux内核,比如coreboot。有的平台可能没有该功能接口,但顶层调用会使用到这个接口,为了不使链接出错,往往就使用到弱符号来解决。使用弱符号函数时,假如此项目工程没有其它同名的函数(可以认为是“强符号”),则调用该函数;如果其它文件也实现了同一名称函数,则调用其它文件的实现函数。

弱符号链接使用很简单,在函数实现加上__attribute__ ((weak))即可。对于调用者来说没有任何区别。下面的示例中,声明了一个名叫foobar,foodummy.c中是弱符号的实现,foo.c是“强符号”的实现,在main.cpp中调用foobar函数。同时将这3个文件编译,并不会出错,执行结果是打印foo.c中的函数。如果只编译main.cpp和foodummy.c,则会调用到foodummy.c的函数。
注:将doodummy.c的weak属性去掉,编译3个文件,编译器报重定义错误。
头文件声明foo.h:

#ifndef FOO_H
#define FOO_H

#ifdef __cplusplus
extern "C" {
#endif

void foobar(void);

#ifdef __cplusplus
}
#endif

#endif // FOO_H

弱符号链接实现文件dummyfoo.c:

#include "foo.h"
#include <stdio.h>

// 弱链接,外部没有实现时,则调用此处函数
void __attribute__ ((weak)) foobar(void)
{
    printf("dummy foobar...\n");
}

真正实现文件foo.cpp:

#include "foo.h"
#include <stdio.h>

void foobar(void)
{
    printf("realy......\n");
}

主函数main.cpp:

#include "foo.h"
#include <stdio.h>
int main(void) 
{
    printf("test of weak link......\n");
    foobar();
    return 0;
}

实际工作中需要使用一套驱动上层接口的库,这套使用用于不同的SOC,不同的业务程序,对外提供的接口形式不变,所有产品可能都有LED灯,但有的产品没有RS485,有的产品没有FLASH,有的产品没有CPLD,等等。如果不希望这套库为每个产品都重新整理一遍所有接口,在此情况下,weak属性将发挥其强大功能。所有接口都有对应的weak的实现,但对于具体的产品,如果没有某一模块,删除其实现,由于存在weak的实现,不会出现找不到函数定义的错误,只需关注真正需要使用的部分接口即可。
当然,如果使用了C++、Java等面向对象的语言实现,完成可以使用接口实现,用子类继承方式进行各个产品的实例化。