不带__weak 标志的函数(Strong函数)无法代替weak函数的问题

文章探讨了C编程中弱函数(weak function)的使用及链接器行为,特别是在armgcc编译环境下,如何解决main函数中定义的强符号未被正确链接的问题。通过调整链接选项或函数实现位置,确保回调函数能够正确重载。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

ctime:2019-12-08 12:24:17 +0900|1575775457

标签(空格分隔): 技术 编程


在C编程中,有时候需要写一些weak函数,用来给用户进行覆盖。

之前写NRF的函数的时候,写了一个__weak void NRF_Receive_Callback(uint8_t * data,int len);

用来给用户重载接收回调函数。然后我在main中,重新写了一个NRF_Receive_Callback,在IAR中编译、工作正常,NRF接收到
数据之后,会调用main中的callback。然而我用arm gcc编译之后,却发现不行,调用的还是原来的weak函数。在网上搜了半天,
有一篇文章说到:

多次试验和搜索,应该就是静态库的函数只有在要被用到的时候,才会被link,但weak symbol相对比较特殊,会先link到weak的function,然后再去找strong的function。因此strong的function实现在静态库里面,并且对应.o里函数也没被其他.o call 到,整个静态库都不会被link进去,因此最后只会选weak function。

应对的方式

A:利用—whole-archive和—no-whole-archive强制静态库被link进去,这样strong函数一定会被收到。缺点是如果lib之间有同名function会打出build error

B:和A类似,利用link选项-u强制某个function被link,但lib和function较多时不好用

作者:612F

链接:https://www.jianshu.com/p/be55f46b0e5e

来源:简书

著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

想了一下确实是,main中的函数都没被其他文件调用,都是他调用别人。

因为对makefile不太熟,我没去修改makefile的编译 链接选项了,直接把回调写到其他文件中,如control.c,测试正常,果然是这个问题。

本文首发于:http://huangzzk.info

### 关于 `__weak` 的概念及其在 C++ 和 Python 中的应用 #### 什么是弱符号 (`__weak`)? 在编译器层面,符号可以分为强符号和弱符号。弱符号允许程序中存在多个同名的定义,而链接器会选择其中一个作为最终使用的版本。这种机制通常用于实现可选功能或者提供默认行为。 在嵌入式开发领域(如 U-Boot 和 Linux Kernel),`__weak` 是一种常用的修饰符,用来标记函数或变量为弱符号[^2]。这意味着如果其他地方提供了相同名称的强符号,则该强符号会被优先使用;如果没有,则回退到弱符号。 --- #### 在 C++ 中如何定义和使用弱函数? 以下是基于 GCC 编译器的一个简单例子: ```cpp // weak_function.cpp #include <iostream> // 声明一个弱函数 extern "C" __attribute__((weak)) void my_weak_function() { std::cout << "Default implementation of weak function." << std::endl; } void call_my_function() { if (my_weak_function) { // 检查是否存在强符号覆盖 my_weak_function(); } else { std::cout << "No strong symbol found, skipping..." << std::endl; } } ``` 在这个例子中: - 如果外部模块重新实现了 `my_weak_function()` 并将其声明为强符号,则此版本将被调用。 - 若没有任何重写发生,默认的弱实现就会生效。 需要注意的是,在标准 C++ 中并没有直接支持类似的特性,因此它依赖特定平台扩展(比如 GNU 的 `__attribute__((weak))` 或 MSVC 下的同方法)。上述代码适用于 GCC/Clang 环境下运行。 --- #### 对于 Python 来说是否有类似的概念呢? 严格意义上讲,Python 具备像 C/C++ 那样的静态绑定阶段以及相应的“弱符号”概念。然而,我们可以通过动态导入或其他设计模式模拟某种形式的行为: 假设有一个插件系统希望让用户能够替换某些默认处理逻辑而强制修改核心库文件本身的话,可以采用如下方式之一——利用 try-except 结构尝试加载用户自定义模块并设置回调路径: ```python try: from user_defined import custom_handler as handler except ImportError: def handler(): print("Using default handler.") handler() ``` 这里展示了即使存在名为 'user_defined' 的包时也会中断执行流程而是转而应用内置方案的情况。这类似于 C 当中的弱引用效果。 另外值得注意的一点是在多线程环境下操作 python 解析器对象(Python Interpreter State),由于全局解释锁(Global Interpreter Lock,GIL)的存在使得同一时刻只有一个原生线程能够在CPython VM内部真正获得控制权去评估字节码指令序列。所以在混合编程场景里务必记得适时管理gil状态以避免潜在死锁风险[^3]. --- ### 总结 虽然两者之间存在着本质区别(C 属底层硬件抽象层面上的操作 而 Py 则偏向高层级脚本语言范畴),但是它们都试图解决同一个问题即灵活性与兼容性的平衡取舍.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值