嵌入式C进阶三 —— weak

首先我们看一下STM32的HAL库中的代码

  代码库中的__weak就是我们今天要谈关键字,这其实不是C语言的关键字,而是一个编译器的关键字。__weak关键字源自于C++,后来被ARMCC以及gcc for arm等编译器实现。

在C语言中,函数和初始化的全局变量(包括显示初始化为0)是强符号,未初始化的全局变量是弱符号。对于强弱符号,有下列三条规则适用:

  • ① 同名的强符号只能有一个,否则编译器报”重复定义”错误。
  • ② 允许一个强符号和多个弱符号,但定义会选择强符号的。
  • ③ 当有多个弱符号相同时,链接器选择占用内存空间最大的那个。

  对于C语言来说,编译器默认函数和初始化了的全局变量为强符号,未初始化的全局变量为弱符号(C++并没有将未初始化的全局符号视为弱符号)。我们也可以通过GCC的”__attribute__((weak))”来定义任何一个强符号为弱符号 ,ARMCC中可以直接使用“__weak”。

int weak1;  
int strong = 1;  
int __attribute__((weak)) weak2 = 2;  
  
int main()  
{  
        return 0;  
}  

上面这段程序中,”weak”和”weak2″是弱符号,”strong”和”main”是强符号 。

  那么这个__weak有什么作用呢?首先说他在STM32的HAL库中修饰的是一个Callback函数,其实就是一个回调函数,用__weak修饰后就是告诉编译器,此函数是一个弱函数,如果编译器找不到一个同名的强函数,那么就调用这个弱函数的实现执行相应弱函数里面的程序。加入用户使用同样的函数名实现了一个强函数,则编译器会优先使用用户自定义的强函数进行连接。

  现在是不是很清楚了,他实际上就是为用户调用或者二次开发提供了便利,有点OOP中的虚函数的感觉。

  其实在另一个例子中我们也会遇到他的一些应用,比如我们常用的printf函数,做单片机开发的时候,经常使用这个函数来将字符串通过串口打印,大家都会遇到一个fput函数的重定向。为什么要重定向呢?

  原因是C语言的库函数实现的printf函数最终是去调用fput函数显示在终端上,在系统函数库中,这个fput就是被__weak修饰的,因此我们就是靠重新实现fput函数来实现将原本打印在终端上的字符串从串口的sendchar函数输出。

You may also like...

发表评论

电子邮件地址不会被公开。