0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

ARM中关键字的具体使用

技术让梦想更伟大 来源:CSDN-ZC·Shou 2023-02-10 15:06 次阅读

今天在使用 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 源码中,该关键字非常常见:

bb8d281c-a862-11ed-bfe3-dac502259ad0.png

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

__attribute__((attribute1,attribute2,...))//例如:void*Function_Attributes_malloc_0(intb)__attribute__((malloc));
__attribute__((__attribute1__,__attribute2__,...))//例如:staticintb__attribute__((__unused__));
12

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

除此之外,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 声明,但是没有定义)。具体看下图的测试代码:

bb9fc3d2-a862-11ed-bfe3-dac502259ad0.png

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

定义

用 __weak 定义的函数弱输出其符号。弱定义的函数的行为类似于正常定义的函数,除非将同名的非弱定义的函数链接到同一镜像中。 如果在同一镜像中同时存在非弱定义函数和弱定义函数,则对该函数的所有调用都会解析为调用非弱函数,否则直接使用弱定义的函数(与上面的若声明不同)。??如果可以使用多个弱定义,则除非使用链接器选项 --muldefweak,否则链接器会生成一条错误消息。在这种情况下,链接器随机选择一个供所有调用来使用。使用方式如下:

/*a.h!!!注意所在文件不同!!!*/
voidFuncA(void);
voidFuncB(void);

/*a.c!!!注意所在文件不同!!!*/
voidFuncA(void)
{
FuncB();/*这里将替换为main.c中的FuncB*/
}

__weakvoidFuncB(void)/*弱定义*/
{

}

/*main.c!!!注意所在文件不同!!!*/
voidFuncB(void)
{

}

intmain(void)
{
FuncB();
}
12345678910111213141516171819202122232425

注意,函数的声明一定不能添加 __weak 关键字。具体如下图:bbede116-a862-11ed-bfe3-dac502259ad0.png

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

限制

函数或变量不能在同一编译中同时弱和非弱地使用。

voidf(void);

voidg()
{
f();/*非弱函数引用*/
}

__weakvoidf(void);

voidh()
{
f();/*弱函数引用*/
}
12345678910111213

不能在定义函数或变量的同一编译中使用弱函数或弱变量,如下将导致编译错误(正确的使用方式参考上面的使用示例):

/*a.c如下同一文件中的定义及使用将报错*/
__weakvoidf(void);

voidh()
{
f();
}

voidf()
{

}
123456789101112

弱函数不能是内联函数

「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)); 声明的文件的中的同名函数定义,都将被当做弱函数。如下图:bc1bde90-a862-11ed-bfe3-dac502259ad0.png

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

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

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

定义

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

__attribute__((weak))voidFuncA(void)
{
printf("WeakFuncA!
");
}
/*或者*/
void__attribute__((weak))FuncA(void)
{
printf("WeakFuncA!
");
}
123456789

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

区别

如上介绍,__weak 和 __attribute__((weak)) 在声明和定义的时候,其所处的位置有不同。

__weak 仅在函数定义中使用时才会生成弱函数。而在任何情况下(声明和定义) __attribute__((weak)) 都会生成弱函数,无论是用于函数定义还是用于函数声明中!

审核编辑:汤梓红

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • ARM
    ARM
    +关注

    关注

    134

    文章

    8653

    浏览量

    361827
  • GCC
    GCC
    +关注

    关注

    0

    文章

    104

    浏览量

    24716
  • 函数
    +关注

    关注

    3

    文章

    3882

    浏览量

    61310
  • 编译器
    +关注

    关注

    1

    文章

    1577

    浏览量

    48624
  • 关键字
    +关注

    关注

    0

    文章

    37

    浏览量

    6841

原文标题:__weak 和 __attribute__((weak)) 关键字的使用

文章出处:【微信号:技术让梦想更伟大,微信公众号:技术让梦想更伟大】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    在NVM和本地\"内存定义数组(静态 /global /local)的\"关键字是什么?

    在 NVM 和本地\"内存定义数组(静态 /global /local)的\"关键字是什么? 还有与 32 位对齐的关键字怎么样。
    发表于 01-25 07:52

    写入FLASH的关键字

    求各位大神,我想写一个数组,放有1024个数,用的是430单片机,RAM肯定放不下,有没有这样一个关键字,直接写入FLASH,急!!!!!!
    发表于 08-15 22:07

    DSP编程技巧之17---非常“关键”的关键字

      const关键字用来定义值不会发生变化/不允许被改变的变量、数组等,即相当于这些变量、数组是“只读”的。通常情况下,const定义的全 局变量会存放在cmd文件定义的.const段,而.const段
    发表于 08-20 11:38

    static 关键字

    static 关键字 浅析
    发表于 01-16 16:55

    C语言关键字专题

    ,相当于BOOKstruct book .如果你觉得你懂了,那么下面这个把BOOK,代表的是什么意思呢?此时的BOOK是一个具体的变量 相当于咱们上面的mybook一样的啦四、static关键字
    发表于 10-24 16:38

    c语言中 volatile _Bool 关键字说明

    volatile 关键字呢?volatile总是与优化有关,编译器有一种技术叫做数据流分析,分析程序的变量在哪里赋值、在哪里使用、在哪里失效,分析结果可以用于常量合并,常量传播等优化,进一步可以消除一些代码
    发表于 01-06 10:46

    嵌入式软件编程关键字的用法和原理

    青岛职业技术学院刘浩山东省文登市泽头镇***张斌引言计算机编程语言的关键字就好比是它的灵魂,只有深入理解了它们的含义才能编写出优秀的代码。C语言以其简洁、高效和强大等特性成为嵌入式软件编程的首选语言
    发表于 06-20 07:37

    “bit”和“control”被识别为关键字

    嗨,我不明白为什么单词“bit”和“control”被涂成关键字。我在别处找不到答案,我之前找到的唯一一篇帖子是在2013年写的,但是这篇文章没有答案。也许它是由netbean定义的,但是我没有找到应用程序di关键字列表。我
    发表于 08-29 08:34

    【原创分享】单片机编程关键字之volatile

    k = i;//④语句volatile关键字告诉编译器,i是随时可能发生改变的。每次使用它的时候必须从内存取出i的值,因而编译器生成的汇编代码会重新从i的地址处读取数据放在k。这样看来,如果i
    发表于 06-29 11:17

    介绍一下关键字extern的用法

    学单片机C语言一定要熟悉关键字的用法,本文介绍一下关键字extern的用法。1、extern的定义是:extern可以置于变量或者函数前,以标示变量或者函数的定义在别的文件,提示编译器遇到此变量
    发表于 07-15 06:38

    C语言volatile关键字详解 精选资料分享

    1.volatile和什么有关百度翻译是这样子翻译volatile的:图1-1 百度翻译volatile截图volatile属于C语言的关键字,《C Primer Puls》 是这样解释关键字的:关键字是C语言的词汇,由于编译器
    发表于 07-22 07:20

    volatile关键字应用场景及示例

    volatile关键字1.应用场景2.示例1.应用场景volatile关键字分析,往往应用在三种场合1)多线程编程共享全局变量的时候,该全局变量要加上volatile进行修饰,让编译器不要优化该变量
    发表于 08-24 07:21

    关键字static的作用是什么

    头文件的ifndef/define/endif 的作用?1.关键字static的作用是什么1). 在函数体,一个被声明为静态的变量在这一函数被调用过程维持其值不变。2). 在模块内(但在函数体外
    发表于 11-09 07:23

    ROMCODE关键字的作用

    ROM,RAM以及code,dataram掉电丢失rom掉电不丢失因为单片机RAM很有限,所以将不变的保存到ROMCODE关键字的作用就是告诉编译器把这些内容写到ROM以 AT89c51 为例
    发表于 12-08 07:51

    IAR能否在整个工程搜索关键字

    像mdk可以在整个工程搜索关键字 IAR应该也有类似的功能吧,但是我貌似没有找到
    发表于 11-08 07:21