自動(dòng)初始化機(jī)制是指初始化函數(shù)不需要被顯式調(diào)用,只需要在函數(shù)定義處通過(guò)宏定義的方式進(jìn)行申明,就會(huì)在系統(tǒng)啟動(dòng)過(guò)程中被執(zhí)行。這篇文章就來(lái)探索一下其中的奧秘, 簡(jiǎn)單理解其原理!
|知識(shí)點(diǎn)補(bǔ)充
__attribute__((section(x)))是GNU C的一個(gè)特色之一,它可以用于將變量或函數(shù)放置在指定的段中。例如,你可以使用__attribute__((section(".my_section")))將變量或函數(shù)放置在名為my_section的段中。這對(duì)于嵌入式系統(tǒng)編程和操作系統(tǒng)內(nèi)核編程非常有用。
__attribute__((used))是GCC編譯器提供的一個(gè)特性,用于告訴編譯器在目標(biāo)文件中保留一個(gè)靜態(tài)變量或函數(shù),即使它沒(méi)有被引用。這樣可以避免鏈接器刪除未使用的節(jié),或者確保某些特定的變量或函數(shù)被輸出。
__attribute__((unused))是GCC編譯器提供的一個(gè)特性,用于告訴編譯器某個(gè)變量或函數(shù)可能未被使用,從而避免編譯器產(chǎn)生未使用變量或函數(shù)的警告。在變量或函數(shù)前加上__attribute__((unused))即可使用該特性。
__attribute__((aligned(n)))是GCC編譯器提供的一個(gè)特性,用于設(shè)置變量、類型、函數(shù)的對(duì)齊方式。它的作用是告訴編譯器在分配內(nèi)存空間時(shí),要求以n個(gè)字節(jié)為邊界。
__attribute__((weak))是GCC編譯器提供的一個(gè)特性,用于聲明或定義一個(gè)弱符號(hào)(weak symbol)。弱符號(hào)是指在鏈接時(shí),如果存在同名的強(qiáng)符號(hào)(strong symbol),則會(huì)被強(qiáng)符號(hào)覆蓋。

| 原理研究
深入研究了一下, 發(fā)現(xiàn)這樣使用宏真的很奇妙, 這里就簡(jiǎn)單介紹一下原理:
export.h文件
#ifndef__EXPORT_H
#define__EXPORT_H
#defineEXPORT_USED__attribute__((used))
#defineEXPORT_SECTION(x)__attribute__((section(x)))
typedefint(*export_init_fn_t)(void);
#defineEXPORT_INIT_EXPORT(fn,level)
EXPORT_USEDconstexport_init_fn_t__export_call_##fnEXPORT_SECTION(".export_call."level)=fn
//板級(jí)初始化順序1
#defineEXPORT_BOARD_INIT(fn)EXPORT_INIT_EXPORT(fn,"1")
//設(shè)備初始化順序3
#defineEXPORT_DEVICE_INIT(fn)EXPORT_INIT_EXPORT(fn,"2")
//組件初始化順序4
#defineEXPORT_COMPONENT_INIT(fn)EXPORT_INIT_EXPORT(fn,"3")
//環(huán)境初始化順序5
#defineEXPORT_ENV_INIT(fn)EXPORT_INIT_EXPORT(fn,"4")
//APP初始化順序6
#defineEXPORT_APP_INIT(fn)EXPORT_INIT_EXPORT(fn,"5")
voidexport_components_init(void);
#endif
export.c文件
#include"export.h"
#include"stdio.h"
staticinttest_0_start(void)
{
return0;
}
EXPORT_INIT_EXPORT(test_0_start,"0");
staticinttest_0_0(void)
{
return0;
}
EXPORT_INIT_EXPORT(test_0_0,"0");
staticinttest_0_1(void)
{
return0;
}
EXPORT_INIT_EXPORT(test_0_1,"0");
staticinttest_0_end(void)
{
return0;
}
EXPORT_INIT_EXPORT(test_0_end,"0.end");
staticinttest_1_start(void)
{
return0;
}
EXPORT_INIT_EXPORT(test_1_start,"1");
staticinttest_1_0(void)
{
return0;
}
EXPORT_INIT_EXPORT(test_1_0,"1");
staticinttest_1_1(void)
{
return0;
}
EXPORT_INIT_EXPORT(test_1_1,"1");
staticinttest_1_end(void)
{
return0;
}
EXPORT_INIT_EXPORT(test_1_end,"1.end");
//自動(dòng)初始化(在main函數(shù)調(diào)用)
voidexport_components_init(void)
{
printf("pfn1:%p
",&__export_call_test_0_start);
printf("pfn2:%p
",&__export_call_test_0_0);
printf("pfn3:%p
",&__export_call_test_0_1);
printf("pfn4:%p
",&__export_call_test_0_end);
printf("pfn5:%p
",&__export_call_test_1_start);
printf("pfn6:%p
",&__export_call_test_1_0);
printf("pfn7:%p
",&__export_call_test_1_1);
printf("pfn8:%p
",&__export_call_test_1_end);
volatileconstexport_init_fn_t*pfn;
for(pfn=&__export_call_test_0_start;pfn&__export_call_test_1_end;?pfn++)
????{
????????printf("%p
",?pfn);
????????//?(*pfn)();
????}
}
結(jié)果輸出:
pfn1:08000c50 pfn2:08000c54 pfn3:08000c58 pfn4:08000c5c pfn5:08000c60 pfn6:08000c64 pfn7:08000c68 pfn8:08000c6c 08000c50 08000c54 08000c58 08000c5c 08000c60 08000c64 08000c68
過(guò)程分析:
這個(gè)測(cè)試代碼片段主要定義和使用了兩個(gè)段,每個(gè)段定義了開始和結(jié)束,并且在開始和結(jié)束間插入了若干個(gè)函數(shù),通過(guò)觀察地址的變化會(huì)發(fā)現(xiàn), 它們是按規(guī)律遞增的,就可以使用遍歷來(lái)調(diào)用指針指向的函數(shù), 從而實(shí)現(xiàn)自動(dòng)初始化外設(shè)的目的.
細(xì)節(jié)分析:
//定義一個(gè)函數(shù)指針
typedefint(*export_init_fn_t)(void);
//宏定義
#defineEXPORT_INIT_EXPORT(fn,level)
EXPORT_USEDconstexport_init_fn_t__export_call_##fnEXPORT_SECTION(".export_call."level)=fn
//假設(shè)調(diào)用
EXPORT_INIT_EXPORT(test_1_0,"1");
//一頓操作后,內(nèi)存就存在了一個(gè)export_init_fn_t__export_call_test_1_0存放在".export_call."的輸入段中,并指定其屬于第一級(jí)初始化段
//就可以通過(guò)指針調(diào)用指針指向的函數(shù)來(lái)調(diào)用指定的函數(shù),實(shí)現(xiàn)自動(dòng)化初始化
|EventOS的EXPORT
這個(gè)先待定, 后續(xù)有時(shí)間再移植,export需要參考elab,涉及到assertcommonexportlog,感興趣的讀者可以參考:

鏈接//gitee.com/event-os/eventos/tree/dev_df/examples/stm32g070
使用了export機(jī)制可以讓代碼變得更加簡(jiǎn)潔,感興趣的讀者可以在理解原理后進(jìn)行完善和優(yōu)化.
審核編輯:湯梓紅
-
GCC
+關(guān)注
關(guān)注
0文章
111瀏覽量
26058 -
開源
+關(guān)注
關(guān)注
3文章
4018瀏覽量
45537 -
函數(shù)
+關(guān)注
關(guān)注
3文章
4405瀏覽量
66797 -
編譯器
+關(guān)注
關(guān)注
1文章
1669瀏覽量
51060 -
宏定義
+關(guān)注
關(guān)注
0文章
51瀏覽量
9363
原文標(biāo)題:開源探索|EventOS之自動(dòng)初始化
文章出處:【微信號(hào):玩轉(zhuǎn)單片機(jī),微信公眾號(hào):玩轉(zhuǎn)單片機(jī)】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
發(fā)布評(píng)論請(qǐng)先 登錄
RT-Thread自動(dòng)初始化詳解
求藍(lán)牙協(xié)議棧初始化和調(diào)度機(jī)制資料?
USART初始化結(jié)構(gòu)體詳解
RT-Thread自動(dòng)初始化機(jī)制簡(jiǎn)介
RT-Thread系統(tǒng)自動(dòng)初始化機(jī)制簡(jiǎn)介
EasyFlash+ulog自動(dòng)初始化的問(wèn)題與解決辦法介紹
手機(jī)模塊初始化向?qū)?/a>
ds1302時(shí)鐘芯片初始化,自動(dòng)決定DS1302是否需要初始化程序
一文詳解RT-Thread自動(dòng)初始化
RT-Thread自動(dòng)初始化機(jī)制
帶初始化的if和switch語(yǔ)句詳解
IM 系列設(shè)備過(guò)載保護(hù)機(jī)制下界面初始化中斷的底層邏輯與解決方案
GraniStudio:初始化例程

自動(dòng)初始化機(jī)制原理詳解
評(píng)論