Toggle navigation
首页
问答
文章
积分商城
专家
专区
更多专区...
文档中心
返回主站
搜索
提问
会员
中心
登录
注册
Kernel
RT-Thread 的 INIT_BOARD_EXPORT(fn) 宏 实现过程
发布于 2017-12-27 19:58:48 浏览:16788
订阅该版
bg8.png由于项目需要,最近也开始接触RTT,小白一枚。如有错误,多多指教。 今天在看RT-Thread启动分析时,遇到了这样一段代码(下面红色代码): ![FastAdmin](https://www.rt-thread.org/qa/static/image/hrline/4.gif) void rt_components_board_init(void) { #if RT_DEBUG_INIT int result; const struct rt_init_desc *desc; for (desc = &__rt_init_desc_rti_board_start; desc < &__rt_init_desc_rti_board_end; desc ++) { rt_kprintf("initialize %s", desc->fn_name); result = desc->fn(); rt_kprintf(":%d done
", result); } #else const init_fn_t *fn_ptr; for (fn_ptr = &__rt_init_rti_board_start; fn_ptr < &__rt_init_rti_board_end; fn_ptr++) { (*fn_ptr)(); } #endif } ![FastAdmin](https://www.rt-thread.org/qa/static/image/hrline/4.gif) 首先 定义了结构体指针 desc 。跟踪他的结构体定义 rt_init_desc 如下(下面红色代码): ![FastAdmin](https://www.rt-thread.org/qa/static/image/hrline/4.gif) #ifdef RT_USING_COMPONENTS_INIT typedef int (*init_fn_t)(void); #ifdef _MSC_VER /* we do not support MS VC++ compiler */ #define INIT_EXPORT(fn, level) #else #if RT_DEBUG_INIT struct rt_init_desc { const char* fn_name; const init_fn_t fn; }; #define INIT_EXPORT(fn, level) \ const char __rti_##fn##_name[] = #fn; \ const struct rt_init_desc __rt_init_desc_##fn SECTION(".rti_fn."level) = \ { __rti_##fn##_name, fn}; #else #define INIT_EXPORT(fn, level) \ const init_fn_t __rt_init_##fn SECTION(".rti_fn."level) = fn #endif #endif #else #define INIT_EXPORT(fn, level) #endif ![FastAdmin](https://www.rt-thread.org/qa/static/image/hrline/4.gif) 它里面 包括 一个 char 类型的指针 和一个 init_fn_t 类型 fn,继续跟踪 init_fn_t 定义 ,发现它为一个函数指针:typedef int (*init_fn_t)(void); 继续回到 第一段代码 ,分析for循环中的东西: for (desc = &__rt_init_desc_rti_board_start; desc < &__rt_init_desc_rti_board_end; desc ++) 可以看到 desc 被&__rt_init_desc_rti_board_start 做了初始化。继续跟踪,程序调到了 这条宏 INIT_EXPORT(rti_board_start, "0.end"); 继续跟踪,又到了第二段代码的蓝色部分。可以看出这个宏是两个 比较牛逼的赋值语句。先分析第一个赋值语句: const char __rti_##fn##_name[] = #fn; **定义了一个char 类型的**__rti_##fn##_name数组。##fn是什么鬼?,其实他没有想象中的那么牛逼,就是一个字符串的拼接。比如 fn为 "gw",那么__rti_##fn##_name就为__rti_gw_name。那#fn是什么意思了? 其实他就是给fn加个“”,让他变成 “fn”,其中fn为具体值,比如fn为gw,那么他是“gw”。 第二个赋值 const struct rt_init_desc __rt_init_desc_##fn SECTION(".rti_fn."level) = { __rti_##fn##_name, fn};如何理解呢?先来分析SECTION(".rti_fn."level)。跟踪SECTION(".rti_fn."level),发现它又是一个宏定义,如下:#define SECTION(x) 其中: __attribute__((section(x))) 是 INIT_BOARD_EXPORT(fn)的精华所在。 关于 它的详细介绍,可以看这篇文章:link:[__attribute__的section用法](http://blog.csdn.net/mloves0729/article/details/14519485) 。下面是我在他文章中截取的部分。 __attribute__的section子项的使用格式为:_attribute__((section("section_name")))其作用是将作用的函数或数据放入指定名为"section_name"输入段。这里还要注意一下两个概念:输入段和输出段输入段和输出段是相对于要生成最终的elf或binary时的Link过程说的,Link过程的输入大都是由源代码编绎生成的目标文件.o,那么这些.o 文件中包含的段相对link过程来说就是输入段,而Link的输出一般是可执行文件elf或库等,这些输出文件中也包含有段,这些输出文件中的段就叫做输 出段。输入段和输出段本来没有什么必然的联系,是互相独立,只是在Link过程中,Link程序会根据一定的规则(这些规则其实来源于Link Script),将不同的输入段重新组合到不同的输出段中,即使是段的名字,输入段和输出段可以完全不同。其用法举例如下:int var __attribute__((section(".xdata"))) = 0;这样定义的变量var将被放入名为.xdata的输入段,(注意:__attribute__这种用法中的括号好像很严格,这里的几个括号好象一个也不能少。) 这一函数指针变量放入什么输入段呢,请看__attribute__ ((__section__ (".initcall" levle ".init"))),输入段的名称由level决定,如果level="1",则输入段是.initcall1.init,如果level="3s",则输入段是.initcall3s.init。这一函数指针变量就是放在用这种方法决定的输入段中的。 然后就简单了。通过__attribute__((section(x))) 修饰后,代码中所有的宏定义 INIT_EXPORT(x,y) 就会编译到一个段里。 如何直观的理解了?可以看自己工程编译后的.map 文件。下面是我用429程序编译后,生成的.map文件中的截图: ![map.png](/uploads/201712/27/193803s6cx1we79bg77ue2.png) 这样这段程序就可以让人理解了。 for (desc = &__rt_init_desc_rti_board_start; desc < &__rt_init_desc_rti_board_end; desc ++) { rt_kprintf("initialize %s", desc->fn_name); result = desc->fn(); rt_kprintf(":%d done
", result); } 而我们在程序里看到的 INIT_BOARD_EXPORT(fn) ,如下面的截图: ![import.png](/uploads/201712/27/194338e68919d1lxndy3s3.png) 跟踪一下,又是一个宏定义:#define INIT_BOARD_EXPORT(fn) INIT_EXPORT(fn, "1")。正好定义成了咱们分析的这个宏。这样我们就明白了INIT_BOARD_EXPORT(fn)到底是怎么被调用的了,真相终于大白了。下图是调试串口的打印截图: ![output.png](/uploads/201712/27/194919b4mahtzld7fai2y8.png) 第一次,写东西,发现表达好难,求吐槽。哈哈~~~~~~~~~~~~~ 2017-12-27 the boy No name [qq]3473527590[/qq]
查看更多
16
个回答
默认排序
按发布时间排序
bigfanofRTOS
2017-12-27
有啥好写的,一边凉快去!
沙发,感谢楼主的分享
bernard
2017-12-28
这家伙很懒,什么也没写!
我被楼主的背景页惊到了
guoweilkd
2017-12-28
这家伙很懒,什么也没写!
>我被楼主的背景页惊到了 --- 求大神带小弟飞
遗失的小许
2017-12-28
这家伙很懒,什么也没写!
背景还可以这样搞 666
emlslxl
2017-12-28
这家伙很懒,什么也没写!
大写的赞
还没想好
2017-12-28
这家伙很懒,什么也没写!
此贴要火!!!占坑留名!
dancingzhang
2018-09-30
这家伙很懒,什么也没写!
楼主写的很好
xiaoqumao
2018-10-17
这家伙很懒,什么也没写!
多谢多谢
我夏了夏天
认证专家
2018-10-17
Life isn't about finding yourself, life is about creating yourself.
特效花了眼 ;P
flyboy
2018-10-18
Do my self();
楼主很生动了表示了——乱花渐欲迷人眼;P
撰写答案
登录
注册新账号
关注者
0
被浏览
16.8k
关于作者
guoweilkd
这家伙很懒,什么也没写!
提问
18
回答
10
被采纳
0
关注TA
发私信
相关问题
1
请教cpu使用率分析
2
选择FreeRTOS, 还是RT-Thread。
3
thread heap stack overflow ?
4
rtt消息队列delay问题
5
释放被删除线程的内存地方在哪里啊
6
请教:各线程结束后,释放其中的内存的连续性问题
7
STM32F103中断关于信号量、邮箱问题
8
RTT中的线程栈大小如何控制
9
关于线程由执行态变为挂起态的代码实现,,,
10
rt_malloc(rt_size_t size)内存分配函数最小分配尺寸问题
推荐文章
1
RT-Thread应用项目汇总
2
玩转RT-Thread系列教程
3
国产MCU移植系列教程汇总,欢迎查看!
4
机器人操作系统 (ROS2) 和 RT-Thread 通信
5
五分钟玩转RT-Thread新社区
6
【技术三千问】之《玩转ART-Pi》,看这篇就够了!干货汇总
7
关于STM32H7开发板上使用SDIO接口驱动SD卡挂载文件系统的问题总结
8
STM32的“GPU”——DMA2D实例详解
9
RT-Thread隐藏的宝藏之completion
10
【ART-PI】RT-Thread 开启RTC 与 Alarm组件
最新文章
1
CherryUSB的bootuf2配置
2
在用clangd开发RTT吗,快来试试如何简单获得清晰干净的工作区
3
GD32F450 片内 flash驱动适配
4
STM32H7R7运行CherryUSB
5
RT-Smart首次线下培训,锁定2024 RT-Thread开发者大会!
热门标签
RT-Thread Studio
串口
Env
LWIP
SPI
AT
Bootloader
Hardfault
CAN总线
FinSH
ART-Pi
USB
DMA
文件系统
RT-Thread
SCons
RT-Thread Nano
线程
MQTT
STM32
RTC
FAL
rt-smart
ESP8266
I2C_IIC
UART
WIZnet_W5500
ota在线升级
PWM
freemodbus
flash
cubemx
packages_软件包
BSP
潘多拉开发板_Pandora
定时器
ADC
flashDB
GD32
socket
中断
编译报错
Debug
SFUD
rt_mq_消息队列_msg_queue
msh
keil_MDK
ulog
C++_cpp
MicroPython
本月问答贡献
a1012112796
12
个答案
1
次被采纳
踩姑娘的小蘑菇
4
个答案
1
次被采纳
红枫
4
个答案
1
次被采纳
张世争
4
个答案
1
次被采纳
Ryan_CW
4
个答案
1
次被采纳
本月文章贡献
catcatbing
3
篇文章
6
次点赞
YZRD
2
篇文章
5
次点赞
lizimu
2
篇文章
5
次点赞
qq1078249029
2
篇文章
2
次点赞
xnosky
2
篇文章
1
次点赞
回到
顶部
发布
问题
分享
好友
手机
浏览
扫码手机浏览
投诉
建议
回到
底部