嵌入式開(kāi)發(fā),離不開(kāi) C 語(yǔ)言,C語(yǔ)言中有很多語(yǔ)法會(huì)直接或間接影響你代碼的質(zhì)量,下面就來(lái)講講__attribute__ 關(guān)鍵字的用法。
1. 什么是 __attribute__
GNU C 編譯器增加了一個(gè) __attribute__ 關(guān)鍵字用來(lái)聲明一個(gè)函數(shù)、變量或類(lèi)型的特殊屬性。申明這些屬性主要用途就是指導(dǎo)編譯程序進(jìn)行特定方面的優(yōu)化或代碼檢查。
__attrabute__ 的用法非常簡(jiǎn)單,當(dāng)我們定義一個(gè)一個(gè)函數(shù)、變量或者類(lèi)型時(shí),直接在他名字旁邊添加如下屬性即可:
__attribute__((ATTRIBUTE))
需要注意的是,__attribute__ 后面是兩對(duì)小括號(hào),不能圖方便只寫(xiě)一對(duì),否則會(huì)編譯報(bào)錯(cuò)。括號(hào)里的 ATTRIUBTE 表示要聲明的屬性,目前支持十幾種屬性聲明:
section:自定義段
aligned:對(duì)齊
packed:對(duì)齊
format:檢查函數(shù)變參格式
weak:弱聲明
alias:函數(shù)起別名
noinline:無(wú)內(nèi)聯(lián)
always_inline:內(nèi)聯(lián)函數(shù)總是展開(kāi)
......
比如:
charc __attribute__((algined(8)))=4; intglobal_val __attribute__((section(".data")));
當(dāng)然,我們對(duì)一個(gè)變量也可以同時(shí)添加多個(gè)屬性。在定義變量前,各個(gè)屬性之間用逗號(hào)隔開(kāi)。以下三種聲明方式是沒(méi)有問(wèn)題的。
charc__attribute__((packed,algined(4))); charc__attribute__((packed,algined(4)))=4; __attribute__((packed,algined(4)))charc=4;
2. 屬性聲明:section
section 屬性的主要作用是:在程序編譯時(shí),將一個(gè)函數(shù)或者變量放到指定的段,即指定的section 中。
一個(gè)可執(zhí)行文件注意由代碼段,數(shù)據(jù)段、BSS 段構(gòu)成。代碼段主要用來(lái)存放編譯生成的可執(zhí)行指令代碼、數(shù)據(jù)段和BSS段用來(lái)存放全局變量和未初始化的全局變量。
除了這三個(gè)段,可執(zhí)行文件還包含一些其他的段。我們可以用 readelf 去查看一個(gè)可執(zhí)行文件各個(gè)section信息。
下表是不同的 section 及說(shuō)明:
section | 組成 |
---|---|
代碼段(.text) | 函數(shù)定義、程序語(yǔ)句 |
數(shù)據(jù)段 (.data) | 初始化的全局變量、初始化的靜態(tài)局部變量 |
BSS 段(.bss) | 未初始化的全局變量,未初始化的靜態(tài)局部變量 |
intglobal_val=8; intunint_val; intmain(void) { return0; }
我們使用gcc 編譯這個(gè)程序:
gcc-m32-o a.out gnu.c
查看符表號(hào)信息:
#readelf-s a.out Num:ValueSize TypeBindVisNdx Name 44:0804c0204OBJECTGLOBAL DEFAULT24unint_val 45:080490904FUNCGLOBAL HIDDEN13__x86.get_pc_thunk.bx 46:0804c0100NOTYPEWEAKDEFAULT23data_start 47:0804c01c0NOTYPEGLOBAL DEFAULT23_edata 48:080491c40FUNCGLOBAL HIDDEN14_fini 49:0804c0184OBJECTGLOBAL DEFAULT23global_val 50:0804c0100NOTYPEGLOBAL DEFAULT23__data_start 51:000000000NOTYPEWEAKDEFAULTUND __gmon_start__ 52:0804c0140OBJECTGLOBAL HIDDEN23__dso_handle 53:0804a0044OBJECTGLOBAL DEFAULT15_IO_stdin_used 54:000000000FUNCGLOBAL DEFAULTUND __libc_start_main@@GLIBC_ 55:0804916085FUNCGLOBAL DEFAULT13__libc_csu_init 56:0804c0240NOTYPEGLOBAL DEFAULT24_end 57:080490801FUNCGLOBAL HIDDEN13_dl_relocate_static_pie 58:0804904055FUNCGLOBAL DEFAULT13_start 59:0804a0004OBJECTGLOBAL DEFAULT15_fp_hw 60:0804c01c0NOTYPEGLOBAL DEFAULT24__bss_start 61:0804915210FUNCGLOBAL DEFAULT13main
查看 section 信息:
#readelf-S a.out
使用 __attribute__ ((section("xxx"))),修改段的屬性。
intglobal_val=0; intunint_val __attribute__((section(".data"))); intmain() { return0; }
可以看到 unint_val 這個(gè)變量,已經(jīng)被編譯器放在數(shù)據(jù)段中。當(dāng)然也可以自定義段的名稱(chēng)。
3. 屬性聲明:aligned
GNU C 通過(guò) __attribute__ 來(lái)聲明 aligned 和 packed 屬性,指定一個(gè)變量或類(lèi)型的對(duì)齊方式。
通過(guò) aligned 屬性,我們可以顯示地指定變量 a 在內(nèi)存中的地址對(duì)齊方式。aligned 有一個(gè)參數(shù),表示要按幾個(gè)字節(jié)對(duì)齊,使用時(shí)要注意,地址對(duì)齊的字節(jié)數(shù)必須是 2 的冪次方,否則編譯就會(huì)報(bào)錯(cuò)。
3.1 地址對(duì)齊
#includeinta=1; intb=2; charc1=3; charc2=4; intmain() { printf("a=%p ",&a); printf("b=%p ",&b); printf("c1=%p ",&c1); printf("c2=%p ",&c2); return0; }
可以看到,char 占一個(gè)字節(jié),c2的地址緊挨著 c1
a=0x404030 b=0x404034 c1=0x404038 c2=0x404039
使用 aligned 地址對(duì)齊
#includeinta=1; intb=2; charc1=3; charc2\__attribute__((aligned(4)))=4; intmain() { printf("a=%p ",&a); printf("b=%p ",&b); printf("c1=%p ",&c1); printf("c2=%p ",&c2); return0; }
可以看到,c2 的地址是按照4字節(jié)對(duì)齊
a=0x404030 b=0x404034 c1=0x404038 c2=0x40403c
通過(guò) aligned 屬性聲明,雖然可以顯示的指定變量地址的對(duì)齊方式,但是也會(huì)因?yàn)檫吔鐚?duì)齊造成一定的內(nèi)存空間浪費(fèi)。
地址對(duì)齊的好處是,為了配合計(jì)算機(jī)硬件設(shè)計(jì),可以簡(jiǎn)化CPU和內(nèi)存RAM之間的接口和硬件設(shè)計(jì)。
例如,一個(gè)32位的計(jì)算機(jī)操作系統(tǒng),在CPU讀取內(nèi)存時(shí),硬件設(shè)計(jì)上可能只支持4字節(jié)或者4字節(jié)倍數(shù)對(duì)齊地址訪問(wèn),CPU 每次向 RAM 讀寫(xiě)數(shù)據(jù)時(shí),一個(gè)周期可以讀寫(xiě)4字節(jié)。如果我們把一個(gè)int型數(shù)據(jù)就放在4字節(jié)對(duì)齊的地址上,那么CPU就可以一次性把數(shù)據(jù)讀取完畢,否則可能需要讀取兩次。
3.2 結(jié)構(gòu)體對(duì)齊
結(jié)構(gòu)體作為一種復(fù)雜的數(shù)據(jù)類(lèi)型,編譯器在給一個(gè)結(jié)構(gòu)體變量分配存儲(chǔ)空間時(shí),不僅要考慮結(jié)構(gòu)體內(nèi)各個(gè)成員的對(duì)齊,還要考慮結(jié)構(gòu)體整體的對(duì)齊。
為了結(jié)構(gòu)體各成員對(duì)齊,編譯器可能會(huì)在結(jié)構(gòu)體內(nèi)填充一些字節(jié)。為了結(jié)構(gòu)體的整體對(duì)齊,編譯器可能會(huì)在結(jié)構(gòu)體的末尾一些空間。
#includestructdata{ chara; intb; short c; }; intmain() { structdatas; printf("size=%d ",sizeof(s)); printf("a=%p ",&s.a); printf("b=%p ",&s.b); printf("c=%p ",&s.c); return0; }
四字節(jié)對(duì)齊:占12字節(jié)
size=12 a=0xffb6c374 b=0xffb6c378 c=0xffb6c37c
結(jié)構(gòu)體成員順序不同,所占大小有可能不同:
#includestructdata{ chara; short b; intc; }; intmain() { structdatas; printf("size=%d ",sizeof(s)); printf("a=%p ",&s.a); printf("b=%p ",&s.b); printf("c=%p ",&s.c); return0; }
四字節(jié)對(duì)齊:占8字節(jié)
size=8 a=0xffa2d9f8 b=0xffa2d9fa c=0xffa2d9fc
顯示的指定成員的對(duì)齊方式:
#includestructdata{ chara; short b __attribute__((aligned(4))); intc; }; intmain() { structdatas; printf("size=%d ",sizeof(s)); printf("a=%p ",&s.a); printf("b=%p ",&s.b); printf("c=%p ",&s.c); return0; }
四字節(jié)對(duì)齊:占12字節(jié)
size=12 a=0xffb6c374 b=0xffb6c378 c=0xffb6c37c
顯示指定結(jié)構(gòu)體對(duì)齊方式:
#includestructdata{ chara; short b; intc; }__attribute__((aligned(16))); intmain() { structdatas; printf("size=%d ",sizeof(s)); printf("a=%p ",&s.a); printf("b=%p ",&s.b); printf("c=%p ",&s.c); return0; }
16字節(jié)對(duì)齊,末尾填充8字節(jié):占16字節(jié)
size=16 a=0xffa2d9f8 b=0xffa2d9fa c=0xffa2d9fc
3.3 編譯器一定會(huì)按照 aligend 指定的方式對(duì)齊嗎?
我們通過(guò)這個(gè)屬性聲明,其實(shí)只是建議編譯器按照這種大小地址對(duì)齊,但不能超過(guò)編譯器允許的最大值。一個(gè)編譯器,對(duì)每個(gè)基本的數(shù)據(jù)類(lèi)型都有默認(rèn)的最大邊界對(duì)齊字節(jié)數(shù),如果超過(guò)了,則編譯器只能按照它規(guī)定的最大對(duì)齊字節(jié)數(shù)來(lái)對(duì)變量分配地址。
4. 屬性聲明:packed
aligned 屬性一般用來(lái)增大變量的地址對(duì)齊,元素之間地址對(duì)齊會(huì)造成一定的內(nèi)存空洞,而packed屬性則正好相反,一般用來(lái)減少地址對(duì)齊,指定變量或類(lèi)型使用最可能小的地址對(duì)齊方式。
顯示的對(duì)結(jié)構(gòu)體成員使用packed
#includestructdata{ chara; short b __attribute__((packed)); intc __attribute__((packed)); }; intmain() { structdatas; printf("size=%d ",sizeof(s)); printf("a=%p ",&s.a); printf("b=%p ",&s.b); printf("c=%p ",&s.c); return0; }
使用最小一字節(jié)對(duì)齊:
size=7 a=0xfff38fb9 b=0xfff38fba c=0xfff38fbc
對(duì)整個(gè)結(jié)構(gòu)體添加packed屬性
structdata{ chara; short b; intc; }__attribute__((packed));
內(nèi)核中的packed、aligned 聲明
在內(nèi)核源碼中,我們經(jīng)常看到aligned 和 packed 一起使用,即對(duì)一個(gè)變量或者類(lèi)型同時(shí)使用packed 和 aligned 屬性聲明。這樣做的好處是即避免了結(jié)構(gòu)體各成員間地址對(duì)齊產(chǎn)生的內(nèi)存空洞,又指定了整個(gè)結(jié)構(gòu)體的對(duì)齊方式。
structdata{ chara; short b; intc; }__attribute__((packed,aligned(8)));
5. 屬性聲明:format
GNU 通過(guò) __attribute__ 擴(kuò)展的 format 屬性,來(lái)指定變參函數(shù)的參數(shù)格式檢查。
它的使用方法如下:
__attribute__((format(archetype,string-index,frist-to-check))) voidLOG(constchar*fmt,...)__attribute__((format(printf,1,2)));
屬性format(printf,1,2) 有3各參數(shù),第一個(gè)參數(shù)pritnf 是告訴編譯器,按照printf的標(biāo)準(zhǔn)來(lái)檢查;第二個(gè)參數(shù)表示LOG()函數(shù)所有的參數(shù)列表中格式字符串的位置索引,第三個(gè)參數(shù)是告訴編譯器要檢查的參數(shù)的起始位置。
LOG("hello world,i am%d ages ",age);/*前者表示格式字符串,后者表示所有的參數(shù)*/
6. 屬性聲明:weak
GNU C 通過(guò) weak 屬性聲明,可以將一個(gè)強(qiáng)符號(hào),轉(zhuǎn)換為弱符號(hào)。使用方法如下:
void__attribute__((weak))func(void); intnum __attribute__((weak));
在一個(gè)程序中,無(wú)論是變量名,還是函數(shù)名,在編譯器眼里,就是一個(gè)符號(hào)而已,符號(hào)可以分為強(qiáng)符號(hào)和弱符號(hào)。
強(qiáng)符號(hào):函數(shù)名,初始化的全局變量名
弱符號(hào):未初始化的全局變量名。
在一個(gè)工程項(xiàng)目中,對(duì)于相同的全局變量名、函數(shù)名,我們一般可以歸結(jié)為以下3種場(chǎng)景:
強(qiáng)符號(hào) + 強(qiáng)符號(hào)
強(qiáng)符號(hào) + 弱符號(hào)
弱符號(hào) + 弱符號(hào)
強(qiáng)符號(hào)和弱符號(hào)主要用來(lái)解決在程序鏈接過(guò)程中,出現(xiàn)多個(gè)同名全局變量、同名函數(shù)的沖突問(wèn)題,一般我們遵循以下3個(gè)原則:
一山不容二虎
強(qiáng)弱可以共處
體積大者勝出
在一個(gè)項(xiàng)目中,不可能同時(shí)存在兩個(gè)強(qiáng)符號(hào)。如果在一個(gè)多文件的項(xiàng)目中定義兩個(gè)同名的函數(shù)后者全局變量,那么連接器在鏈接時(shí)就會(huì)報(bào)重定義錯(cuò)誤。
但是,在一個(gè)工程中允許強(qiáng)符號(hào)和弱符號(hào)同時(shí)存在,比如可以定義一個(gè)初始化的全局變量和一個(gè)未初始化的全局變量,這種寫(xiě)法在編譯時(shí)是可以編過(guò)的。
編譯器對(duì)這種同名符號(hào)沖突時(shí),在做符號(hào)決議時(shí),一般會(huì)選擇強(qiáng)符號(hào),丟掉弱符號(hào)。
還有一種情況是,在一個(gè)工程中,當(dāng)都是弱符號(hào)時(shí),那么編譯器該選擇哪個(gè)呢?誰(shuí)在內(nèi)存中存儲(chǔ)空間大,就選誰(shuí)。
變量的弱符號(hào)與強(qiáng)符號(hào)
//func1.c inta=1; intb; voidfunc(void) { printf("func.a=%d ",a); printf("func.b=%d ",b); } //main.c inta; intb=2; voidfunc(); intmain() { printf("main.a=%d ",a); printf("main.b=%d ",b); func(); return0; }
編譯后,程序運(yùn)行結(jié)果如下??梢钥闯龃蛴〉亩际菑?qiáng)符號(hào)的值。
main.a=1 main.b=2 func.a=1 func.b=2
一般不建議在一個(gè)工程中定義多個(gè)不同類(lèi)型的同名弱符號(hào),編譯時(shí)可能會(huì)出現(xiàn)各種各樣的問(wèn)題。也不能同時(shí)定義兩個(gè)同名的強(qiáng)符號(hào),否則會(huì)報(bào)重定義錯(cuò)誤。我們可以使用GNU C 的擴(kuò)展 weak 屬性,將一個(gè)強(qiáng)符號(hào)轉(zhuǎn)換為弱符號(hào)。
inta __attribute__((weak))=1;
函數(shù)的強(qiáng)符號(hào)與弱符號(hào)
鏈接器對(duì)于同名的函數(shù)沖突,同樣遵循相同的規(guī)則。函數(shù)名本身是一個(gè)強(qiáng)符號(hào),在一個(gè)工程中定義兩個(gè)同名的函數(shù),編譯器肯定會(huì)報(bào)重定義錯(cuò)誤。但是,我們可以通過(guò)weak 屬性聲明,將其中的一個(gè)函數(shù)名轉(zhuǎn)換為弱符號(hào)。
//func1.c inta __attribute__((weak))=1; voidfunc(void) { printf("func.a=%d ",a); } //main.c inta=4; void__attribute__((weak))func(void) { printf("main.a=%d ",a); } intmain(void) { func(); return0; }
弱符號(hào)的用途
在一個(gè)源文件中引用一個(gè)編號(hào)或者函數(shù),當(dāng)編譯器只看到聲明,而沒(méi)看到其定義時(shí),一般編譯時(shí)不會(huì)報(bào)錯(cuò)。在鏈接階段,鏈接器會(huì)到其他文件中找到這些符號(hào)的定義,若未找到,則報(bào)未定義錯(cuò)誤。
當(dāng)函數(shù)被聲明一個(gè)弱符號(hào)時(shí),會(huì)有一個(gè)奇特地方:當(dāng)鏈接器找不到這個(gè)函數(shù)的定義時(shí),也不會(huì)報(bào)錯(cuò)。編譯器會(huì)將這個(gè)函數(shù)名,即弱符號(hào),設(shè)置為0或者一個(gè)特殊值。只有當(dāng)程序運(yùn)行時(shí),調(diào)用到這個(gè)函數(shù),跳轉(zhuǎn)到零地址或者一個(gè)特殊的地址才會(huì)報(bào)錯(cuò)誤,產(chǎn)生一個(gè)內(nèi)存錯(cuò)誤。
如果我們?cè)谑褂煤瘮?shù)前,判斷這個(gè)函數(shù)地址是否為0,即可避免段錯(cuò)誤。你會(huì)發(fā)現(xiàn),即使函數(shù)未定義也可以正常編過(guò)。
弱符號(hào)的這個(gè)特性在庫(kù)函數(shù)開(kāi)發(fā)設(shè)計(jì)中應(yīng)用十分廣泛,如果在開(kāi)發(fā)一個(gè)庫(kù)時(shí),基礎(chǔ)功能已經(jīng)實(shí)現(xiàn),有些高級(jí)功能還未實(shí)現(xiàn),那么你就可以將這些函數(shù)通過(guò)weak 屬性聲明轉(zhuǎn)換為一個(gè)弱符號(hào)。
7. 屬性聲明:alias
GNU C 擴(kuò)展了一個(gè) alias 屬性,這個(gè)屬性很簡(jiǎn)單,主要用來(lái)給函數(shù)定義一個(gè)別名。
void__f(void) { printf("__f "); } voidf(void)__attribute__((alias("__f"))); intmain(void) { f(); return0; }
在Linux 內(nèi)核中你會(huì)發(fā)現(xiàn)alias有時(shí)候會(huì)和weak屬性一起使用。如有些接口隨著內(nèi)核版本升級(jí),函數(shù)接口發(fā)生了變化,我們可以通過(guò)alias屬性對(duì)舊的接口名字進(jìn)行封裝,重新起一個(gè)接口名字。
//f.c void__f(void) { printf("__f "); } voidf()__attribute__((weak,alias("__f"))); //main.c void__attribute__((weak))f(void); voidf(void) { printf("f "); } intmain() { f(); return0; }
如果我們?cè)趍ain.c 中定義了f()函數(shù),那么main 函數(shù)調(diào)用f()會(huì)調(diào)用薪定義的函數(shù),否則調(diào)用__f()函數(shù)。
8. 屬性聲明:noinline 和 always_inline
8.1 什么是內(nèi)聯(lián)函數(shù)
說(shuō)起內(nèi)聯(lián)函數(shù),就不得不說(shuō)起函數(shù)調(diào)用開(kāi)銷(xiāo)。一個(gè)函數(shù)在執(zhí)行過(guò)程中,如果要調(diào)用其他函數(shù),則一般會(huì)執(zhí)行以下過(guò)程:
保存當(dāng)前函數(shù)現(xiàn)場(chǎng)
跳到調(diào)用函數(shù)執(zhí)行
恢復(fù)當(dāng)前函數(shù)現(xiàn)場(chǎng)
繼續(xù)執(zhí)行當(dāng)前函數(shù)
對(duì)于一些短小精悍,并且調(diào)用頻繁的函數(shù),調(diào)用開(kāi)銷(xiāo)大,這個(gè)時(shí)候我們可以將函數(shù)聲明為內(nèi)聯(lián)函數(shù)。編譯器遇到內(nèi)聯(lián)函數(shù)會(huì)想宏一樣將內(nèi)聯(lián)函數(shù)之間在調(diào)用處展開(kāi),這樣做就減少了函數(shù)調(diào)用的開(kāi)銷(xiāo)。
8.2 內(nèi)聯(lián)函數(shù)與宏
與宏相比,內(nèi)聯(lián)函數(shù)有以下優(yōu)勢(shì):
參數(shù)類(lèi)型檢查:內(nèi)聯(lián)函數(shù)本質(zhì)上還是一個(gè)函數(shù),在編譯過(guò)程中編譯器會(huì)對(duì)齊進(jìn)行參數(shù)檢查,而宏不具備這個(gè)特性。
便于調(diào)試:函數(shù)支持的調(diào)試功能有斷點(diǎn)、單步等。
返回值:內(nèi)聯(lián)函數(shù)有返回值。這個(gè)優(yōu)勢(shì)是相對(duì)于ANSI C 說(shuō)的。因?yàn)楝F(xiàn)在的宏也有返回值和類(lèi)型了,如使用語(yǔ)句表達(dá)式定義的宏。
接口封裝:有些內(nèi)聯(lián)函數(shù)可以用來(lái)封裝一個(gè)接口,而宏不具備這個(gè)特性。
8.3 編譯器對(duì)內(nèi)聯(lián)函數(shù)的處理
我們雖然可以通過(guò)inline 關(guān)鍵字將一個(gè)函數(shù)聲明為一個(gè)內(nèi)聯(lián)函數(shù),但是編譯器不一定會(huì)對(duì)這個(gè)函數(shù)內(nèi)聯(lián)展開(kāi)。編譯器也要根據(jù)實(shí)際情況進(jìn)行評(píng)估,權(quán)衡展開(kāi)和不展開(kāi)的利弊,并最終決定要不要展開(kāi)。
內(nèi)聯(lián)函數(shù)并不是完美的,也有一些缺點(diǎn)。內(nèi)聯(lián)函數(shù)會(huì)增大程序的體積。
一般而言判斷一個(gè)內(nèi)聯(lián)函數(shù)是否展開(kāi),從程序員的角度主要從以下幾點(diǎn)出發(fā):
函數(shù)體積小
函數(shù)體內(nèi)無(wú)指針賦值、遞歸、循環(huán)語(yǔ)句等
調(diào)用頻繁
當(dāng)我們認(rèn)為一個(gè)函數(shù)體積小、而且被大量調(diào)用,應(yīng)做內(nèi)聯(lián)展開(kāi)時(shí),就可以使用static inline 關(guān)鍵字修飾它,但是編譯器不一定會(huì)內(nèi)聯(lián)展開(kāi)。如果想明確告訴編譯器一定要展開(kāi),或者不展開(kāi)就可以使用 noinline 和 always_inline 對(duì)函數(shù)的屬性做一個(gè)聲明。
8.4 內(nèi)聯(lián)函數(shù)為什么定義在頭文件中?
在Linux 內(nèi)核中,你會(huì)看到大量的內(nèi)聯(lián)函數(shù)被定義在頭文件中,而且常常使用static關(guān)鍵字修飾。
為什么定義在頭文件中呢?因?yàn)樗且粋€(gè)內(nèi)聯(lián)函數(shù),可以像宏一樣使用,在任何想使用內(nèi)聯(lián)函數(shù)的源文件中,都不必親自在定義一遍,直接包含這個(gè)頭文件即可。
為什么還要用static 修飾呢?因?yàn)槭褂胕nline關(guān)鍵字定義的內(nèi)聯(lián)函數(shù),編譯器不一定會(huì)內(nèi)聯(lián)展開(kāi),那么當(dāng)一個(gè)工程中多個(gè)頭文件包含這個(gè)內(nèi)聯(lián)函數(shù)的定義時(shí),編譯時(shí)就可能報(bào)重復(fù)定義的錯(cuò)誤。使用satic 關(guān)鍵字修飾,則可以限定這個(gè)函數(shù)的作用域在各自的源文件內(nèi),避免重復(fù)定義的發(fā)生。
9. 總結(jié)
本文主要介紹了 GNU C 的擴(kuò)展語(yǔ)法 __attributr__ 關(guān)鍵字,并對(duì)其中常用的屬性聲明做了詳細(xì)的介紹:
section
packed
aligned
format
alias
weak
noinline
always_inline
審核編輯:劉清
-
RAM
+關(guān)注
關(guān)注
8文章
1368瀏覽量
114640 -
C語(yǔ)言
+關(guān)注
關(guān)注
180文章
7604瀏覽量
136684 -
嵌入式開(kāi)發(fā)
+關(guān)注
關(guān)注
18文章
1028瀏覽量
47563 -
BSS
+關(guān)注
關(guān)注
0文章
18瀏覽量
12210 -
GNU
+關(guān)注
關(guān)注
0文章
143瀏覽量
17492
原文標(biāo)題:嵌入式C代碼屬性怎么定義?
文章出處:【微信號(hào):玩點(diǎn)嵌入式,微信公眾號(hào):玩點(diǎn)嵌入式】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論