-
2018-11-02 09:49:51
我们不确定外部模块是否提供一个函数func,但是我们不得不用这个函数。
一、问题声明
extern int func(void); //声明函数,告诉编译器不要管 ................... int a = func(); //使用函数 ...................
这会导致2个结果:
1:外部存在这个函数func,并且EXPORT_SYMBOL(func),那么在我自己的模块使用这个函数func,正确。
2:外部其实不存在这个函数,那么我们使用func,程序直接崩溃。
二、如何解决
所以这个时候,__attribute__((weak)) 派上了用场。
在自己的模块中定义:
int __attribute__((weak)) func(......)
{
return 0;
}
将本模块的func转成弱符号类型,如果遇到强符号类型(即外部模块定义了func),那么我们在本模块执行的func将会是外部模块定义的func。类似于c++中的重载如果外部模块没有定义,那么,将会调用这个弱符号,也就是在本地定义的func,直接返回了一个1(返回值视具体情况而定)
相当于增加了一个默认函数。
原理:
注: 连接器发现同时存在弱符号和强符号,有限选择强符号,如果发现不存在强符号,只存在弱符号,则选择弱符号。如果都不存在:静态链接,恭喜,编译时报错,动态链接:对不起,系统无法启动。
weak属性只会在静态库(.o .a )中生效,动态库(.so)中不会生效。
举个例子:strong.c //生成libstrong.so #include <stdio.h> void real_func() { printf("int real func\n"); } weak.c //生成libweak.so #include <stdio.h> void real_func() __attribute__((weak)); void real_func() { printf("fake func\n"); } main.c // #include <stdio.h> extern void real_func(); void main() { real_func(); }
如果
gcc main.c -lstrong -lweak
那么输出结果"real func"。
如果
gcc main.c -lweak -lstrong
那么输出结果为"fake func"。
可见,对于动态库,weak属性毫无作用,且main中调用哪个real_func(),取决于顺序。
如果将strong.c 和 weak.c编译成.a或者.o
gcc main.c strong.o weak.o
或者
gcc main.c weak.o strong.o
那么输出结果都是"real func"。
所以,如果在so中使用weak属性,那么任何不符合预期的情况,都是可能出现的。
官方解释:
https://sourceware.org/bugzilla/show_bug.cgi?id=3946
更多相关内容 -
ARM 之十一__weak 和 __attribute__((weak)) 关键字的使用
2020-06-17 19:53:19之前对于 __weak 关键字一直是一个简单的认知:编译器自动使用没有 __weak 的同名函数(如果有的话)替换有 __weak 关键字的同名函数,__weak 函数可以没有定义,且编译器不会报错! 至于这个参数详细的使用细节一直...今天在使用 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 源码中,该关键字非常常见:
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 声明,但是没有定义)。具体看下图的测试代码:
注意:用__weak
声明然后不使用__weak
定义的函数的行为相当于非弱函数。 这与_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
关键字。具体如下图:
注意:用
__weak
声明然后不使用__weak
定义的函数的行为相当于非弱函数。 这与_attribute__((weak))
关键字不同!限制
- 函数或变量不能在同一编译中同时弱和非弱地使用。
void f(void); void g() { f(); /* 非弱函数引用 */ } __weak void f(void); void h() { f(); /* 弱函数引用 */ }
- 不能在定义函数或变量的同一编译中使用弱函数或弱变量,如下将导致编译错误(正确的使用方式参考上面的使用示例):
/* 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))
进行定义的函数的行为就像是弱函数。 这与__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
关键字的用法不同。除此之外,没有啥不同,这里不再多说!区别
- 如上介绍,
__weak
和__attribute__((weak))
在声明和定义的时候,其所处的位置有不同。 __weak
仅在函数定义中使用时才会生成弱函数。而在任何情况下(声明和定义)__attribute__((weak))
都会生成弱函数,无论是用于函数定义还是用于函数声明中!
参考
- https://community.arm.com/developer/tools-software/tools/f/keil-forum/34584/run-error-when-use-__weak-to-define-function
- https://blog.csdn.net/rensheng__rumeng/article/details/78634804
- http://blog.sina.com.cn/s/blog_62d3426b0100g7n6.html
- http://www.keil.com/support/man/docs/armcc/armcc_chr1359124970859.htm
- http://infocenter.arm.com/help/topic/com.arm.doc.dui0472j/DUI0472J_armcc_user_guide.pdf
- https://github.com/ARM-software/CMSIS_5/issues/141
-
C:__attribute__ weak 的作用
2020-01-11 23:33:55`weak`经常出现在各种`c`代码中,其作用是将当前文件的对应函数声明为弱函数符号,如果外部文件出现相同的函数名,最终编译出来的 文件会优先指向外部文件的函数符号。关于 weak
weak
经常出现在各种c
代码中,其作用是将当前文件的对应函数声明为弱函数符号,如果外部文件出现相同的函数名,最终编译出来的
文件会优先指向外部文件的函数符号;
通常需要使用__attribute__
,不知道标准C有没有这样的用法;具体如下所示;void foo(void) __attribute__ ((weak, warn_unused_result));
或者
__attribute__ ((weak, warn_unused_result)) void foo(void);
看
Freertos
的源码的时候,发现了它;
看glibc
的源码的时候,发现了它;
测试
于是为了一探究竟,简单地写了一下代码测试;
a.c
中的foo(void)
函数为弱定义;b.c
中的foo(void)
函数为强定义;
a.c
b.h
b.c
gcc *.c *.h -o test && chmod +x test
最终输出结果显示
b.c,foo,4
可见打印的信息的foo
函数在b.c
的第四行;所以,b.c
中的foo
函数作为强函数符号,最终被编译到可执行程序中;可以最终结果验证前面的结论。 -
__attribute__((weak))介绍以及用法
2021-04-29 14:47:23WEAK __attribute__((weak)) WEAK 函数声明在没有链接算法库时能编译通过 弱符号函数使模块的函数转换为弱符号类型,连接器发现同时存在弱符号和强符号,优先选择强符号,如果发现不存在强符号。只存在弱符号,则...什么是强符号和弱符号?
在c语言中,函数和初始化的全局变量是强符号,未初始化的全局变量是弱符号。强符号和弱符号的定义是连接器用来处理多重定义符号的,它的规则是:不允许多个强符号;如果一个强符号和一个弱符号,这选择强符号;如果多个弱符号,则任意选一个。
使用__attribute__((weak))的场景
A,B两个模块,A模块调用了,但是不确定B模块是否提供了函数,但是又不得不调用,这个时候在A模块中再申明一个弱符号函数,即用weak,如果外部提供了调用外部的,如果没提供调用申明的。在工作当中就是在保证在没有链接某个库时能编译通过。假设现在有一个库,支持a、b、c三种模式,并且同时只能有一种模式生效,可以适配三种类型的设备。如果想要a模式,那就没有必要去链接b、c模式依赖的库,像调用普通函数一样,肯定会报函数未定义错误,因为你没有链接相关库。这时我们只需要把函数在本模块声名时都加上__attribute__((weak)),这样链接就可以通过。(在这种情况,必须得确保a模式下,程序运行中不会调用b、c模式的函数,否者会造成程序崩溃,因为你没有链接相关库,函数是没有定义的,只是欺骗编译器让编译通过)
attribute((weak))的作用:
弱符号函数使模块的函数转换为弱符号类型,连接器发现同时存在弱符号和强符号,优先选择强符号,如果发现不存在强符号。只存在弱符号,则选择弱符号。
#示例代码:
#include <stdio.h> void __attribute__((weak)) func(); //extern void func(); void main() { if(func != NULL) { func(); } }
代码解析:
当我们用__attribute__((weak))修饰func()函数后,func就是一个弱符号。不管外部是否定义了func()我们都可以链接通过,当外部定义了就调用外部的func函数,当外部没有定义时就调用本模块的func函数。但实际上本模块并没有定义func函数,所以在调用时我们判断一下函数指针是否为空,以免造成段错误。如果我们用extern来声名函数,当外部没有定义该函数时就会报错,导致编译不过。
-
AttributeError: 'NoneType' object has no attribute '_free_weak_ref'
2022-03-21 22:51:40问题遇到的现象和发生背景 在使用pycharm跑yovol5的里面的简单样例coco128时,几轮都跑完了,但是在跑的过程中,一直在报AttributeError: 'NoneType' object has no attribute '_free_weak_ref'的错误,同时在runs/... -
__attribute__((weak)) 妙用
2021-06-11 16:12:53本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 ...The keyword attribute allows you to specify special properties of variables, function parameters, or structure, union, and, in C++, class members -
AttributeError: ‘NoneType‘ object has no attribute ‘_free_weak_ref
2022-03-29 13:56:01我在跑YOLOv5的代码时出现以上问题。 -
__attribute__((weak))
2020-08-20 13:23:40弱引用:对于GCC,使用__attribute__((weak))关键字来声明的函数称为弱引用。对外部目标文件的符号引用在目标文件被最终链接成可执行文件时,如果没有找到该符号的定义,链接器不会认为它是一个错误,程序可以正常... -
运行YOLOv3报错AttributeError: ‘NoneType‘ object has no attribute ‘_free_weak_ref‘解决办法
2022-04-11 21:13:34在运行Ultralytics的YOLOv3代码时报错’NoneType’ object has no attribute ‘_free_weak_ref’。我搭建的环境是python=3.8版本。网上也没有很好的解决办法。 官方要求python>=3.6。我把python降低到3.7版本成功... -
C语言--__attribute__((weak))
2019-01-11 10:26:281、在其他文件中定义要调用的函数 main.c文件 #include<...char __attribute__((weak))Fun_Sum(char a, char b) { return a + b; } int main(int argc, char *argv[]) { char sum1 = 0; ... -
linux gcc _attribute__((weak)) 简介及作用
2019-03-12 13:54:43最新在看项目新架构代码上看到了有使用到weak,以前没有看到过,所以写一篇文章以作记录。 场景: A,B两个模块,A模块调用了不确定B模块是否提供了函数,但是又不得不调用,这个时候在A模块中再申明一个弱符号函数... -
__attribute__((weak)) 简介及作用
2018-10-13 11:49:25最新在看项目新架构代码上看到了有使用到weak,以前没有看到过,所以写一篇文章以作记录。 场景: A,B两个模块,A模块调用了不确定B模块是否提供了函数,但是又不得不调用,这个时候在A模块中再申明一个弱符号函数... -
iOS弱引用表 SideTable weak_table_t weak_entry_t
2022-01-07 14:32:58} 三、weak_table_t 用来保存弱引用,是个结构体,里面有4个属性, struct weak_table_t { weak_entry_t *weak_entries;//保存每个对象的弱引用的数组, size_t num_entries;//数组的元素个数 uintptr_t mask;//weak_... -
__attribute__((weak))是什么意思
2018-12-23 18:49:56最近在阅读tcmalloc代码时发现使用了很多__attribute__((weak)),上网搜了以下有所了解。 弱符号: 若两个或两个以上全局符号(函数或变量名)名字一样,而其中之一声明为weak symbol(弱符号),则这些全局符号不会... -
__attribute__((weak)):弱引用,可以不实现
2020-02-10 18:20:16#define __weak __attribute__((weak)) //变量加上weak时,是弱符号。函数加上weak时,是弱引用,可以不实现。 //给函数加上weak属性时,即使函数没定义,函数被调用也可以编译成功。 //当有两个函数同名时,则使用... -
’NoneType’ object has no attribute '_free_weak_ref。
2022-04-04 17:12:26用yolov5做图像识别蹦出来这个’NoneType’ object has no attribute '_free_weak_ref。 用yolov5s训练没有问题,但是用yolov5m训练就不行了。显卡是rtx2060的。虚拟内存也给了70g。 -
yolov5训练过程中AttributeError: ‘NoneType‘ object has no attribute ‘_free_weak_ref‘解决办法
2022-06-17 11:50:021.可能为pytorch版本问题 2.batch_size设置大小问题 3.parser.add_argument(’–workers’, type=int, default=0, help=‘max dataloader workers (per RANK in DDP mode)’... -
__attribute__((weak)) 简介及作用(弱引用)
2020-07-29 07:36:07强引用和弱引用 另参考: https://blog.csdn.net/q2519008/article/details/82774774 -
#pragma weak与__attribute__((weak))
2021-01-19 16:36:42#pragma weak name 使 name 成为弱符号。链接程序没有找到 name 的符号定义时,...__attribute__((weak)) 将本模块的func转成弱符号类型,如果遇到强符号类型(即外部模块定义了func),那么我们在本模块执行的func -
GNU C++ 智能指针23- 解析__weak_count类1
2021-10-08 10:22:50目录 一、关键点解析 1、_Sp_counted_base<...3、__weak_count(const __weak_count<_Lp>& __r) noexcept 二、源码分析 一、关键点解析 1、_Sp_counted_base<_Lp>* _M_pi; __sh... -
弱符号__attribute__((weak))
2021-05-19 00:50:21弱符号:若两个或两个以上全局符号(函数或变量名)名字一样,而其中之一声明为weak symbol(弱符号),则这些全局符号不会引发重定义错误。链接器会忽略弱符号,去使用普通的全局符号来解析所有对这些符号的引用,但当... -
GCC __attribute__ 之weak,alias属性
2017-12-01 10:23:29__attribute__ ((weak, alias(”__foo”))); weak 和 alias 分别是两个属性。 weak 使得 foo 这个符号在目标文件中作为 weak symbol 而不是 global symbol 。用 nm 命令查看编译 dummy.c 生成的... -
__attribute__ 之weak,alias属性
2015-01-26 22:39:48Weak Alias 跟 Weak Reference 完全没有任何关系,不过是我在看到 Weak Reference 的时候想到的而已。 Weak Alias 是 gcc 扩展里的东西,实际上是函数的属性。这个东西在库的实现里面可能会经常用到,比如 glibc ... -
GNU C中的__attribute__关键字
2021-04-12 16:33:13__attribute__机制是GNU C中一个非常有用的特性,它可以用来修饰函数、变量和结构体的...__attribute__((weak)) /* 用来声明weak function */ __attribute__((aligned(4))) /* 设置字节对齐 */ __attribute__((packe -
C语言之__weak函数前缀
2018-06-20 11:28:33__weak是一个宏,和__packed是同一种东西都是gcc的扩展属性:#define __packed __attribute__((packed))#define __weak __attribute__((weak))如果这个关键字用在函数定义上面,一般情况下和一般函数没有两样。... -
__attribute__ 机制使用
2020-09-23 10:50:20这是属性经常看见,但是也没仔细的看...attribute 可以设置函数属性(Function Attribute)、变量属性(Variable Attribute)和类型属性(Type Attribute)。 __attribute 是GCC的特性,LLVM借鉴过来,又对其进行了扩 -
GNU __attribute__浅析
2020-06-03 16:57:36GNU __attribute__浅析 1 介绍 __attribute__是GCC的特性,其实是个编译器指令,告诉编译器声明的特性,或者让编译器进行更多的错误检查和高级优化。attribute 可以设置函数属性(Function Attribute)、变量属性... -
C语言__attribute__
2020-03-06 13:54:41可以设置函数属性(Function Attribute )、变量属性(Variable Attribute ) 和类型属性(Type Attribute )。 关键字__attribute__ 也可以对结构体(struct )或共用体(union )进行属性设置。大致有六个参数...