# 工欲善其事必先利其器-C语言拓展--嵌入式C语言(八)
工欲善其事必先利其器-C语言拓展–嵌入式C语言(八)
继续来看看新的属性:weak
这个符号知道是弱,但是这个是干嘛的呢?我们先来学习一下强符号和弱符号
文章内容全部来自–>《嵌入式C语言自我修养——从芯片、编译器到操作系统》 王利涛前辈的,超级推荐
强符号和弱符号
GNU C通过weak属性声明,**可以将一个强符号转换为弱符号。**使用方法如下。
void __attribute__((weak)) func(void);
int num __attribute__((weak))
一个程序中,无论是变量名,还是函数名,在编译器的眼里,就是一个符号而已。符号可以分为强符号和弱符号。
● 强符号:函数名,初始化的全局变量名。
● 弱符号:未初始化的全局变量名。
在一个工程项目中,对于相同的全局变量名、函数名,我们一般可以归结为下面3种场景。
● 强符号+强符号。
● 强符号+弱符号。
● 弱符号+弱符号。
强符号和弱符号主要用来解决在程序链接过程中,出现多个同名全局变量、同名函数的冲突问题。一般我们遵循下面3个规则。
● 一山不容二虎。
● 强弱可以共处。
● 体积大者胜出。
在一个项目中,不能同时存在两个强符号。如果你在一个多文件的工程中定义两个同名的函数或全局变量,那么链接器在链接时就会报重定义错误。
但是在一个工程中允许强符号和弱符号同时存在,如你可以同时定义一个初始化的全局变量和一个未初始化的全局变量,这种写法在编译时是可以编译通过的。
编译器对于这种同名符号冲突,在做符号决议时,一般会选用强符号,丢掉弱符号。
还有一种情况就是,在一个工程中,当同名的符号都是弱符号时,那么编译器该选择哪个呢?谁的体积大,即谁在内存中的存储空间大,就选谁。
不建议在一个工程中定义多个不同类型的同名弱符号,编译的时候可能会出现各种各样的问题。
在一个工程中,也不能同时定义两个同名的强符号,否则就会报重定义错误。
可以使用GNU C扩展的weak属性,将一个强符号转换为弱符号。
链接器对于同名函数冲突,同样遵循相同的规则。函数名本身就是一个强符号,在一个工程中定义两个同名的函数,编译时肯定会报重定义错误。
那弱符号能干嘛呢?
在一个源文件中引用一个变量或函数,当编译器只看到其声明,而没有看到其定义时,编译器一般编译不会报错:编译器会认为这个符号可能在其他文件中定义。
在链接阶段,链接器会到其他文件中找这些符号的定义,若未找到,则报未定义错误。
当函数被声明为一个弱符号时,会有一个奇特的地方:当链接器找不到这个函数的定义时,也不会报错。编译器会将这个函数名,即弱符号,设置为0或一个特殊的值。只有当程序运行时,调用到这个函数,跳转到零地址或一个特殊的地址才会报错,产生一个内存错误。
为了防止函数运行出错,我们可以在运行这个函数之前,先进行判断,看这个函数名的地址是不是0,然后决定是否调用和运行,这样就可以避免段错误了。
弱符号的这个特性,在库函数中应用得很广泛。如你在开发一个库时,基础功能已经实现,有些高级功能还没实现,那么你可以将这些函数通过weak属性声明转换为一个弱符号。通过这样设置,即使还没有定义函数,我们在应用程序中只要在调用之前做一个非零的判断就可以了,并不影响程序的正常运行。等以后发布新的库版本,实现了这些高级功能,应用程序也不需要进行任何修改,直接运行就可以调用这些高级功能。
(我还没做好,低调点,等我做好了就理直气壮了)
还有个alias
这个属性很简单,主要用来给函数定义一个别名。
在Linux内核中,你会发现alias有时会和weak属性一起使用。如有些函数随着内核版本升级,函数接口发生了变化,我们可以通过alias属性对这个旧的接口名字进行封装,重新起一个接口名字。
这不是就不用修改函数了,如果我们在main.c中新定义了f()函数,那么当main()函数调用f()函数时,会直接调用main.c中新定义的函数;当f()函数没有被定义时,则调用__f()函数。
这些逻辑还是有点意思
【内容来源】全部来自《嵌入式C语言自我修养》
# 工欲善其事必先利其器-C语言拓展--嵌入式C语言(八)相关推荐
- 工欲善其事必先利其器-C语言拓展–嵌入式C语言(一)
工欲善其事必先利其器-C语言拓展–嵌入式C语言(一) 我是golang出生,当时做项目的时候java.c++.js.python都折腾过,但是关于c语言的接触,基本上都停留在大一的那个暑假.后来因为要 ...
- # 工欲善其事必先利其器-C语言拓展--嵌入式C语言(九)
工欲善其事必先利其器-C语言拓展–嵌入式C语言(九) 文章内容全部来自–><嵌入式C语言自我修养--从芯片.编译器到操作系统> 王利涛前辈的,超级推荐 内联函数 这个万一就是真的有点 ...
- # 工欲善其事必先利其器-C语言拓展--嵌入式C语言(四)
工欲善其事必先利其器-C语言拓展–嵌入式C语言(四) 零长度数组 零长度数组.变长数组都是GNU C编译器支持的数组类型. 什么是零长度数组? 首先肯定长度是为0的数组 ANSI C规定定义一个数组长 ...
- # 工欲善其事必先利其器-C语言拓展--嵌入式C语言(三)
工欲善其事必先利其器-C语言拓展–嵌入式C语言(三) typeof() 使用typeof可以获取一个变量或表达式的类型. typeof的参数有两种形式:表达式或类型. int i;typeof(i) ...
- 一文了解C语言与嵌入式C语言的区别
嵌入式系统是各行各业的具体应用相结合的产物.例如计算机技术.半导体技术.电子技术. 其更在乎效率和内存有效使用.嵌入式系统是一个技术密集.资金密集.高度分散.不断创新的知识集成系统. C语言是目前世界 ...
- 嵌入式c语言移植,嵌入式C语言位操作的移植方法
单片机的应用越来越广泛,种类也越来越多.由于嵌入式C语言可读性强.移植性好,与汇编语言相比大大减轻了软件工程师的劳动强度,因而越来越多的单片机工程师开始使用C语言编程.但C语言的可移植性仅限于与硬件无 ...
- 嵌入式c语言移植,嵌入式c语言位操作的移植与优化.doc
嵌入式C语言位操作的移植与优化 导语:?由于嵌入式C语言可读性强.移植性好,与汇编语言相比大大减轻了软件工程师的劳动强度,因而越来越多的单片机工程师开始使用C语言编程. 引言 单片机的应用越来越广泛, ...
- 嵌入式培训c语言编程,嵌入式C语言学习秘诀
嵌入式C语言学习秘诀 大家都知道C语言是整个嵌入式开发学习中一门重要的语言,所以学好C语言也是嵌入式开发学习中重要环节.到底如何学习C语言?C语言学习的秘诀是什么?今天本为就为大家揭开这个谜底.学习C ...
- status c语言_STM32 嵌入式C语言教程--第四课C语言中的存储空间与位域
1.存储空间--堆和栈的区别 一个由C/C++编译的程序占用的内存分为以下几个部分 1.栈区(stack)- 由编译器自动分配释放 ,存放函数的参数值,局部变量的值等.其操作方式类似于数据结构中的栈. ...
最新文章
- node - 非阻塞的异步 IO
- impala jdbc驱动执行impala sql的一个坑(不支持多行sql)
- 在linux系统中 用于配置和显示,在Linux系统中使用sway设置多个显示器/监视器
- mysql主主 主键冲突_mysql主从复制原理,主主复制时主键冲突解决
- vue中在当前组件中定义的全局变量怎么在methods中使用_Vue原理解析(十):搞懂事件API原理及在组件库中的妙用...
- php自己编译扩展,Linux编译PHP添加扩展库的方法
- zabbix 通过 SNMP 监控 Windows主机
- AngularJs学习笔记--directive
- 【ManageEngine】局域网监控软件是什么,有什么作用
- linux内核mtd驱动程序与sd卡驱动程序,Linux内核MTD驱动程序及SD卡驱动程序.doc
- 为什么相关不等于因果
- 全国社会组织信用信息公式平台(试运行)爬虫记录
- 【学术论文】查找论文、查找并理解配套代码(持续更新~)
- Flask源码阅读(六)——Flash消息
- 2023英伟达显卡排名天梯图(已更新)
- 筒仓计算表格_筒仓世界中的开源极客
- Java JDK 1.8 新特性 Stream流
- 北斗导航 | 城市环境下,结合ARAIM和3D城市模型用于多星座GNSS伪距观测的完好性监测(论文分析)
- WindowBlinds 11 - Windows 11 系统美化工具软件下载
- 【狄拉克量子力学原理】【2】动力学变量
热门文章
- ble4.2空口包详解(air interface packets)
- FMA20180529
- 两大数据库安全产品比拼:IBM Guardium VS Imperva SecureSpher
- java--阿拉伯数字转中文数字
- 机械革命Umi电脑蓝屏怎么U盘重装系统操作分享
- HGETALL key
- 传奇3的WIL文件格式
- ubuntu14.04+cuda7.0+opencv2.4.9
- winmail中web界面破除用户限制
- 家族关系查询系统程序设计算法思路_数据结构课程设计(家族关系查询系统)..doc...