__weak关键字
之前注意到过它,但一直没有出什么问题,也就没有再深究。但遇到一个关于它的问题,rtt在调用时,调用了weak声明的函数,而没有调用cubemx自动生成的函数,这样就没有启动设备的时钟,造成工作不正常,要不是一步步仿真,才发现此问题,这种问题不好找,也不太能想到。
问题
weak解决什么问题??
__weak 关键字应用于函数和变量声明以及函数定义。 在GUN或MDK 链接时优先链接定义为非 weak 的函数或变量,如果找不到则再链接 weak 函数。
解决程序耦合问题,若程序中有部分代码是需要别人完成的,那可以先用__weak声明,占个位置(占位后,编译器可先不解析这段代码,并且也不会报错,相当于只是一个symbol)。这样别人写好后,再加入到程序中,而不用做任何修改,编译器会自动执行新加入的代码。
linux及RTT中,这样场景很多,尤其是使用cubemx后自动生成代码。需要cube生成的代码,往往会以这种方式引入到OS中
使用规则
- 同名的强符号只能有一个,否则编译器报"重复定义"错误。
- 允许一个强符号和多个弱符号,但定义会选择强符号的。
- 当有多个弱符号相同时,链接器选择占用内存空间最大的那个。
- 如果使用 __weak 声明函数,但随后没有使用 __weak 对其进行定义,则此函数与非弱函数的行为相同。
对于C语言来说,编译器默认函数和初始化了的全局变量为强符号,未初始化的全局变量为弱符号(C++并没有将未初始化的全局符号视为弱符号)。
使用例子
如在rtt中定义HAL_TIM_PWM_MspInit为需要cubemx生成的函数,则直接在驱动文件中定义
__weak void HAL_TIM_PWM_MspInit(TIM_HandleTypeDef *htim)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(htim);
/* NOTE : This function should not be modified, when the callback is needed,
the HAL_TIM_PWM_MspInit could be implemented in the user file
*/
}
arm中的weak使用
因为mdk 本身就是armcc编译器,所以看看mdk中定义就知道weak到底是如何定义的。打开stm32xx_hal_def.h,可以看到weak定义如下:
#if defined ( __GNUC__ ) && !defined (__CC_ARM) /* GNU Compiler */
#ifndef __weak
#define __weak __attribute__((weak))
#endif /* __weak */
#ifndef __packed
#define __packed __attribute__((__packed__))
#endif /* __packed */
#endif /* __GNUC__ */
可见ARM 编译器(armcc)中,支持和 GCC 相同的关键字 attribute。