STM32 HAL库中有很多使用__weak修饰的函数。比如在"stm32f4xx_hal_spi.c"中有一处函数定义:
/**
* @brief Initialize the SPI MSP.
* @param hspi pointer to a SPI_HandleTypeDef structure that contains
* the configuration information for SPI module.
* @retval None
*/__weak void HAL_SPI_MspInit(SPI_HandleTypeDef *hspi){ /* Prevent unused argument(s) compilation warning */
UNUSED(hspi); /* NOTE : This function should not be modified, when the callback is needed,
the HAL_SPI_MspInit should be implemented in the user file
*/}
此处的函数修饰符__weak其实是一个宏定义,定义如下:
#define __weak __attribute__((weak))
__attribute__((weak))用于告诉链接器此处的函数为弱引用,这样一来,如果在其地方有同样的函数定义,则链接器会选择没用__attribute__((weak))修饰的那个函数来链接。这个特性对于需要使用回调函数的地方非常友好,可以在函数库中用__weak实现一个最小化的回调函数,这样用户可以根据是否需要回调而决定是否自己实现回调函数,在用户不需要实现自己的回调函数时,也不会因为缺少函数定义而报错。
在使用__weak时,遇到过2个坑,下面给大家一个参考。
1.使用__weak和不使用__weak修饰的函数不能放在同一个源文件中,否则会报函数重复定义的错误。不过这个也好理解,因为__weak是给链接器做指示用的而非编译器 。当二者存在于同一源文件中,编译器会报错。
2.在__weak修饰的函数中,不能使用while(1)来阻塞程序。如果使用了while(1),编译能通过,但在存在非__weak修饰的函数情况下,程序也依旧无法继续向下执行。这应该是MDK的一个bug。解决方法是先定义一个值为1的局部变量,然后while这个局部变量。
uint8_t tmp = 1;while(tmp);
|