_attribute__((weak))关键字如何使用?

_attribute__((weak))关键字如何使用?之前对于 weak 关键字一直是一个简单的认知 编译器自动使用没有 weak 的同名函数替换有 weak 关键字的同名函数 weak 函数可以没有定义 且编译器不会报错

大家好,欢迎来到IT知识分享网。

今天在使用 Keil (主要是 armcc 编译器)编译代码(华大的 MCU 驱动库hc32f46x_interrupts.h / c)的时候遇到了有 __weak 关键字的函数不起作用的问题,甚是奇怪。之前对于 __weak 关键字一直是一个简单的认知:编译器自动使用没有 __weak 的同名函数(如果有的话)替换有 __weak 关键字的同名函数,__weak 函数可以没有定义,且编译器不会报错!至于这个参数详细的使用细节一直是一知半解,今天借此机会,以 GCC 作为对比,来学习一下 ARM 中的 __weak 关键字的具体使用!

来源

使用过 GCC 以及有 linux 编程经验的人,对于这个关键字应该不陌生。GNU 的编译器(gcc)扩展了一个关键字 attribute,通过该关键字,用户可以在声明时指定特殊的属性,使用时该关键字后跟双括号内的属性,例如:attribute((属性名字))。属性名字都是定义好的,Weak 属性就是其中之一:attribute((weak))。在 linux 源码中,该关键字非常常见:

_attribute__((weak))关键字如何使用?

GCC 不多介绍,重点关注 ARM。在 ARM 编译器(armcc)中,支持和 GCC 相同的关键字 attribute,使用方式也基本相同,如下:

__attribute__((attribute1, attribute2, ...)) // 例如:void * Function_Attributes_malloc_0(int b) __attribute__((malloc)); __attribute__((__attribute1__, __attribute2__, ...)) // 例如:static int b __attribute__((__unused__)); 

当函数属性发生冲突时,编译器将使用更安全或更强的一个

除此之外,ARM 编译器(armcc)还扩展了一个关键字 __weak,例如:__weak void f(void); 或者 __weak int i;。ARM 的汇编器(armasm)以另一种方式 [WEAK]支持该特性。

注意:

在许多源码中,经常通过宏定义的形式来定义关键字,例如 上面linux 中的__weak就是 宏定义的 __attribute__((weak))

强/弱符号

在 GCC 中,被__attribute__((weak))修饰的符号,我们称之为 弱符号(Weak Symbol)。例如:弱函数、弱变量;没有__attribute__((weak))修饰的符号被称为强符号。在 ARM 中,没有弱符号和强符号这种叫法,只有个弱引用(Weak References)和 非弱引用(non-weak reference ) 、 弱定义(Weak definitions)和 非弱定义(non-weak definition)的介绍章节。 非弱引用就是我们平常使用的对于非弱函数或者弱变量的引用。如果链接器无法在到目前为止已加载内容中解析对正常非弱符号的引用问题,则 它会尝试通过在库中找到符号 来解决此问题:

  • 如果找不到此类引用,则链接器将报告错误。
  • 如果解析了这样的引用,则从入口点可以通过至少一个非弱引用来访问的节区被标记为已使用。这样可以确保链接器不会将该节作为未使用的节删除。每个非弱引用都必须通过一个定义来解决。如果有多个定义,则链接器将报告错误。

弱引用

引用弱声明的函数或者变量的引用即为弱引用。链接器不会从库中加载对象来解析弱引用。仅当由于其他原因在镜像中包含了定义时,它才能解析弱引用。弱引用不会导致链接器将包含定义的节区标记为已使用,因此链接器可能会将其标记为未使用而删除。

__weak

__weak 关键字可以应用于函数和变量的声明以及函数定义。

声明

__weak 可以用于函数声明或者变量的声明。对于声明,此存储类指定一个 extern 对象声明,即使该对象不存在,对于该声明的引用也不会导致链接器对未解析的引用(找不到定义的引用)当做错误来处理。

如果在当前编译单元中可以找到 __weak 声明定义,则会用找到的定义替换 __weak 引用;对于找不到定义 __weak 的声明(函数或变量,如上图的 FuncB),编译器做如下处理:

  • 引用被解析为分支连接指令 BL。等效于将被引用的分支为 NOP
  • 直接将引用替换为 NOP 指令 注意:必须是在当前编译单元,不再当前编译单元的没有意义(例如 ExtFuncA 在 main.c 中只有__weak 声明,但是没有定义)。具体看下图的测试代码:
_attribute__((weak))关键字如何使用?

注意:用 __weak 声明然后不使用 _weak 定义的函数的行为相当于非弱函数。这与 attribute((weak)) 关键字不同!

【嵌入式物联网单片机学习】嵌入式物联网开发需要学的东西比较多,大家可以加下面微信一起学习,整理了100多G(全网最全)的学习资料包(持续更新)、最新的学习路线思维导图。

各种学习群、项目开发教程。还可以围观我朋友圈中的一手行业消息,每周的技术大咖直播答疑吹水。

点击这里加我嵌入式物联网单片机学习

_attribute__((weak))关键字如何使用?

定义

用 __weak 定义的函数弱输出其符号。弱定义的函数的行为类似于正常定义的函数,除非将同名的非弱定义的函数链接到同一镜像中。如果在同一镜像中同时存在非弱定义函数和弱定义函数,则对该函数的所有调用都会解析为调用非弱函数,否则直接使用弱定义的函数(与上面的若声明不同)。

如果可以使用多个弱定义,则除非使用链接器选项 –muldefweak,否则链接器会生成一条错误消息。在这种情况下,链接器随机选择一个供所有调用来使用。使用方式如下:

/* a.h !!!注意所在文件不同!!! */ void FuncA(void); void FuncB(void); /* a.c !!!注意所在文件不同!!! */ void FuncA(void) { FuncB(); /* 这里将替换为 main.c 中的 FuncB */ } __weak void FuncB(void) /* 弱定义 */ { } /* main.c !!!注意所在文件不同!!! */ void FuncB(void) { } int main (void) { FuncB(); } 

注意,函数的声明一定不能添加 __weak 关键字。具体如下图:

_attribute__((weak))关键字如何使用?

限制

  • 1数或变量不能在同一编译中同时弱和非弱地使用
void f(void); void g() { f(); /* 非弱函数引用 */ } __weak void f(void); void h() { f(); /* 弱函数引用 */ } 
  • 2.不能在定义函数或变量的同一编译中使用弱函数或弱变量,如下将导致编译错误(正确的使用方式参考上面的使用示例):
/* a.c 如下同一文件中的定义及使用将报错 */ __weak void f(void); void h() { f(); } void f() { } 

弱函数不能是内联函数

attribute((weak))

__attribute__关键字使您可以指定变量或结构字段,函数和类型的特殊属性(与具体属性)。该关键字的作用与 __weak 的作用基本是一样的,在使用时有些不同,此外在某些情况下,编译的处理也有些区别。

声明

这个参数是 GUN 编译器的一个扩展,ARM 编译器也支持该关键字。__attribute__((weak))可以声明弱变量,并且其声明方式与 __weak相比更加灵活。除了__weak 的声明方式,我们还可以用 extern int
Variable_Attributes_weak_1 __attribute__((weak));

_attribute__((weak))可以声明弱函数,其声明方式与__weak相比更加灵活。除了 __weak的声明方式,我们还可以用 extern int
Function_Attributes_weak_0 (int b) __attribute__((weak));。

任何包含了__attribute__((weak)); 声明的文件的中的同名函数定义,都将被当做弱函数。如下图:

_attribute__((weak))关键字如何使用?

开篇提出的问题就是因为上图所示的这种情况!

注意:用 __attribute__((weak))声明然后不使用__attribute__((weak))进行定义的函数的行为就像是弱函数。这与__weak关键字的用法不同。

在 GNU 模式中需要 extern 限定符。在非 gnu 模式下,编译器假设如果变量不是 extern,那么它将像对待其他非弱变量一样对待。

定义

用 __attribute__((weak))定义的函数弱输出其符号(与__weak相同)。其使用方式有以下两种:

__attribute__((weak)) void FuncA(void) { printf("Weak FuncA!\r\n"); } /* 或者 */ void __attribute__((weak)) FuncA(void) { printf("Weak FuncA!\r\n"); } 

注意:用__attribute__((weak))声明然后不使用__attribute__((weak))进行定义的函数的行为就像是弱函数。这与__weak关键字的用法不同。除此之外,没有啥不同,这里不再多说!

区别

  • 1.如上介绍,__weak和__attribute__((weak))在声明和定义的时候,其所处的位置有不同。
  • 2.__weak仅在函数定义中使用时才会生成弱函数。而在任何情况下(声明和定义)__attribute__((weak))都会生成弱函数,无论是用于函数定义还是用于函数声明中!

原文链接:
https://mp.weixin..com/s/I58bnlZfpjmu4Hb6dmz7tg

文章转载自:嵌入式大杂烩

文章来源于:_attribute__((weak))关键字如何使用?

原文链接:__attribute__((weak))关键字如何使用?

版权声明:本文来源于网络,免费传达知识,版权归原作者所有,如涉及作品版权问题,请联系我进行删除

免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://haidsoft.com/169482.html

(0)
上一篇 2025-02-07 09:00
下一篇 2025-02-07 09:05

相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注微信