_weak 弱函数

一、修饰函数

两个重要点:
1、__weak__attribute__((weak)) 在声明和定义的时候,其所处的位置有不同。
2、__weak 仅在函数定义中使用时才会生成弱函数。而在任何情况下(声明和定义) __attribute__((weak)) 都会生成弱函数,无论是用于函数定义还是用于函数声明中!

        用户可以在用户文件中重新定义一个同名函数,最终编译器编译的时候,会选择用户定义的函数,如果用户没有重新定义这个函数,那么编译器就会执行__weak声明的函数,并且编译器不会报错。所以我们可以在别的地方定义一个相同名字的函数,而不必也尽量不要修改之前的函数。

        表示弱声明,若外部文件没有声明EXTI0_IRQHandler函数,则在编译链接的阶段,链接本汇编起始startup_stm32f40_41xxx.s文件即启动代码中的EXTI0_IRQHandler函数。反之,链接外部文件中的EXTI0_IRQHandler函数。

__weak void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
  /* Prevent unused argument(s) compilation warning */
  UNUSED(GPIO_Pin);

  /* NOTE: This function should not be modified, when the callback is needed,
            the HAL_GPIO_EXTI_Callback could be implemented in the user file
   */ 
}

从这个函数中的语句和注释来看,这个函数其实什么都没有做。
我们需要在用户文件中,自己再定义一个一模一样的函数,只是我们自己定义的函数,不需要指明是弱函数。

void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
  if (GPIO_Pin == GPIO_PIN_13)
  {
    /* Toggle LED2 */
    HAL_GPIO_TogglePin( GPIOA,  GPIO_PIN_5);
   
  }
}

        程序在编译的时候,如果发现有两个相同名称的函数,而且其中一个是弱函数,就会忽略弱函数,使用正常的函数进行编译;如果发现只有一个弱函数,那还是会使用弱函数参与编译。

/* test1.c */
#include <stdio.h>

void HelloFun(void)
{
    printf("my hello.");
}

/* test2.c */
#include <stdio.h>

#define __weak __attribute__((weak))

__weak void HelloFun(void)
{
    printf("default hello.");
}

void main(void)
{
    HelloFun();
}

        ​__weak void HelloFun(void)函数和void HelloFun(void)函数不能在同一个.c文件中(当然,如果在同一个文件中,就没有了什么意义。因为弱函数一般用于几个模块之间的交互接口,哪有把几个模块写一个文件中的)。上面的程序中,如果我们在test1.c中没有定义HelloFun()函数,则编译器会使用test2.c中的HelloFun()函数。因此程序会打印default hello.如果在test1.c中定义了HelloFun()函数。则打印my hello.

        c99并没有__weak关键字。此关键字是编译器外扩的。所以不同的编译器可能不一样。比如gcc编译链中并没有这个关键字。而是使用__attribute__((weak))代替。为了方便移植,我们可以宏定义,如下:

#ifndef __weak
#define __weak __attribute__((weak))
#endif

        原理:连接器发现同时存在弱符号和强符号,有限选择强符号,如果发现不存在强符号,只存在弱符号,则选择弱符号。如果都不存在:静态链接,编译时会报错,动态链接:系统无法启动。

        综上所述:如果我们没有在工程中其他地方重新定义 HAL_GPIO_EXTI_Callback()函数,那么 HAL_Init 初始化函数执行的时候, 会默认执行 stm32f4xx_hal.c 文件中定义的 HAL_GPIO_EXTI_Callback函数,而这个函数没有任何控制逻辑。
如果用户在工程中重新定义函数 HAL_GPIO_EXTI_Callback,那么调用 HAL_Init 之后,会执行用户自己定义的 HAL_GPIO_EXTI_Callback函数而不会执行 stm32f4xx_hal.c 默认定义的函数。也就是说,表面上我们看到函数 HAL_GPIO_EXTI_Callback被定义了两次,但是因为有一次定义是弱函数,使用了__weak修饰符,所以编译器不会报错。

weak属性只会在静态库(.o .a )中生效,动态库(.so)中不会生效。

从上面的外部中断函数看出,_weak弱函数声明经常会出现在回调函数当中。

1、回调函数(钩子函数)

概念:函数实现方,不方便直接调用该函数, 而是有函数接口提供方简介调用该函数,称为回调函数
示例: 系统中的信号处理函数,就是一个比较典型的回调函数
1

二、修饰变量(了解)

不持有对象,所以在超出其变量作用域时,对象即被释放
使用方式

__weak int i
__attribute__((weak)) 可以声明弱变量,并且其声明方式与 __weak 相比更加灵活。
extern int Variable_Attributes_weak_1 __attribute__((weak));

        修饰变量在代码编写用的比较少。
        循环引用容易发生内存泄漏。所谓的内存泄漏就是应当废弃的对象在其作用域之外继续存在。
此代码的本意是赋予变量 test0 的对象 A 和赋予变量 test1 的对象 B 在超出其变量作用域时被释放,即在对象不被任何变量持有的状态下予以废弃。但是,循环引用使得对象不能被再次废弃。
        以下情况,虽然只有一个对象,也会出现循环引用:

id test = [[Test alloc] init];

[test setObject:test];

        因为带 __weak 修饰符的变量(即弱引用)不持有对象,所以在超出其变量作用域时,对象即被释放。如果像以下内容将可能发生循环引用的类成员变量改成附有 __weak 修饰符的成员变量的话,该现象是可以避免的。
原文:_weak修饰符详解

@inerface Test : NSObject

{

id __weak obj_;

}

  • (void)setObject:(id __strong)obj;

@end

  • 32
    点赞
  • 75
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
### 回答1: compare_exchange_weak是C++11中的一个原子操作函数,用于比较并交换操作。它可以在多线程环境下保证数据的原子性,避免出现数据竞争的情况。与compare_exchange_strong相比,它的版本在交换操作失败时不会抛出异常,而是返回一个bool值表示操作是否成功。 ### 回答2: compare_exchange_weak是C++中的原子操作函数之一。它的作用是比较给定的值和内存中的值,如果相等,则将内存中的值替换为一个新的值。 compare_exchange_weak函数的使用方式如下: ``` bool compare_exchange_weak(T& expected, T desired); ``` 其中,expected是一个引用参数,表示期望的值;desired是新的值。函数首先比较内存中的值和expected,如果相等,则将内存中的值替换为desired并返回true;如果不相等,则将内存中的值赋给expected并返回false。 compare_exchange_weak函数的比较和替换原子操作。之所以称为"",是因为它在比较和替换期间可能会受到其他线程的干扰,需要重试。这种重试可以保证代码的正确性,但可能会影响性能。 与之相对的是compare_exchange_strong函数,它是"强"的比较和替换原子操作。compare_exchange_strong函数不需要重试,因此使用起来更简单,但有可能导致不必要的循环开销。 需要注意的是,compare_exchange_weak函数的返回值不仅表示比较和替换的结果,还表示内存中的值是否被替换。因此,在使用该函数时,需要根据返回值判断操作是否成功。 总之,compare_exchange_weak是C++中的原子操作函数,用于比较给定值和内存中的值,并在相等时替换。它是一种的比较和替换操作,可能需要重试以保证正确性。 ### 回答3: compare_exchange_weak是一种原子操作,其目的是在多线程环境下实现对共享变量的原子比较和交换操作。在C++中,compare_exchange_weak函数通常与一个参数一起使用,该参数用于表示预期值。此函数会比较共享变量的值与预期值是否相等,如果相等,则将共享变量的值修改为新值,返回true;如果不相等,则不进行修改,返回false。 与compare_exchange_strong函数相比,compare_exchange_weak函数在性能上可能略有优势,但在并发度较高的情况下,可能会出现一些问题,因为它可能会被其他线程中断,导致原子操作失败。在这种情况下,函数会返回false,但同时还会返回共享变量的当前值,并将预期值修改为当前值。 compare_exchange_weak函数通常与循环结合使用,以确保原子操作的成功。在循环中,可以不断尝试进行原子操作,直到成功为止。这种方法可以有效地避免由于竞态条件而导致的共享变量值的错误结果。 总而言之,compare_exchange_weak函数是一种用于实现原子比较和交换操作的方式。尽管它在某些情况下可能会失败,但通过循环的方式,我们可以确保操作的成功,并保证共享变量的一致性。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Yank_k

点个关注加分享,一起探讨学习!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值