什么是弱函数,它们有什么用途?我正在使用stm32f429微控制器。

30
维基百科上说:

弱符号是在可执行文件和可链接格式(ELF)目标文件链接期间特殊注释的符号。默认情况下,没有任何注释的目标文件中的符号都是强符号。在链接期间,强符号可以覆盖同名的弱符号。相比之下,共享名称的两个强符号在链接时间会产生链接错误。在链接二进制可执行文件时,一个弱声明的符号不需要定义。相比之下,(默认情况下)已声明的强符号而没有定义会触发未定义符号链接错误。C或C++语言标准没有提到弱符号;因此,在代码中插入它们并不是很可移植。即使两个平台支持相同或类似的标记符号为弱符号的语法,其语义也可能有微妙的差异,例如运行时动态链接期间的弱符号是否失去其语义。

什么是弱函数及其用途?我正在使用stm32f429微控制器。库中存在一些弱函数。但是我无法理解它们及其用途!

我在谷歌上搜索了它,但没有得到令人满意的答案。

4个回答

56

当一个函数以__weak描述符开头时,它基本上意味着如果您(编码者)未定义它,则在此处定义它。

让我们看一下我的死对头“HAL_UART_RxCpltCallback()”。

此函数存在于可从ST-Micro下载的STM32F4-HAL代码库的HAL中。

在文件stm32f4xx_hal_uart.c中,您将找到此函数的定义:

__weak void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
  /* NOTE: This function Should not be modified, when the callback is needed,
       the HAL_UART_RxCpltCallback could be implemented in the user  file
  */
}

因此,正如代码中的注释所说,将此函数放在您自己的用户文件中。但是在这样做时,请不要加入__weak术语。这意味着链接器将采用您对HAL_UART_RxCpltCallback()函数的定义,而不是stm32f4xx_hal_uart.c文件中定义的函数。

这使得通用代码库始终能够编译。您不必编写大量您不感兴趣的功能,但它仍然可以编译。当该轮到编写您自己的函数时,您只需要将其定义为__weak和编写即可。

简单易懂?有帮助吗?

干杯!


6
假设我们有一个常见的(库)协议接口 protocol.c,在接收数据时我们希望在通信接口 com.c 中执行特定的应用程序逻辑。这可以通过使用弱函数来解决。
/// protocol.h
void protocol_recCallback(protocol_t *prt);

/// protocol.c
__weak void protocol_recCallback(protocol_t *prt) {}

void protocol_rx(protocol_t *prt)
{
  // Common protocol interface
  protocol_recCallback(prt);  // This will call application specific function in com.c
}

/// com.c
#include "protocol.h"

void protocol_recCallback(protocol_t *prt)
{
  // Application specific code is executed here
}

优势: 如果com.c中未定义函数protocol_recCallback(),链接器将不会输出未定义的引用并调用__weak函数。


3

__weak 函数是可以被同名用户函数重写的方法,用于定义向量表和默认处理程序。

常规函数编写(声明和定义)被认为是强类型的,这意味着函数名称不能被重新声明,否则会导致编译器/链接器错误。

将函数声明为 __weak 类型,则可以被用户代码覆盖掉。

void USART1_IRQHandler (void) __attribute__ ((weak, alias("Default_Handler")));

uint32_t vectors[75] __attribute__((section(".isr_vector")));

vectors[0] = STACK_START;
vectors[52] = USART1_IRQHandler;

void Default_Handler(void) {
  while(1);
}


uart1.c (user code)

void USART1_IRQHandler(){
    ...
}

在上面的示例代码中,USART1_IRQHandler被定义为弱函数并别名为Default_handler。 用户可以使用相同的名称覆盖此函数,而不会出现任何编译器/链接器错误,如果用户在uart1.c中定义USART1_IRQHandler,则将使用这个新的函数定义。

2
除了"This gives the generic code base the ability to always compile."之外,__weak还允许您在不触及__weak + less回调函数代码的情况下,在CubeMX中重新生成您的代码。 如果您将代码编写为:
__weak void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
  /* NOTE: This function Should not be modified, when the callback is needed,
       the HAL_UART_RxCpltCallback could be implemented in the user  file
  */
}

由于某些原因在Cubemx中重新生成,你的代码将会崩溃!


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接