linux源碼中staticinline的分析
《linux源碼中staticinline的分析》由會(huì)員分享,可在線(xiàn)閱讀,更多相關(guān)《linux源碼中staticinline的分析(7頁(yè)珍藏版)》請(qǐng)?jiān)谘b配圖網(wǎng)上搜索。
1、文檔供參考,可復(fù)制、編制,期待您的好評(píng)與關(guān)注! 【賽迪網(wǎng)訊】inline屬性在使用的時(shí)候,要注意以下兩點(diǎn):inline關(guān)鍵字在GCC參考文檔中僅有對(duì)其使用在函數(shù)定義(Definition)上的描述,而沒(méi)有提到其是否能用于函數(shù)聲明(Declare)。 從inline的作用來(lái)看,其放置于函數(shù)聲明中應(yīng)當(dāng)也是毫無(wú)作用的:inline只會(huì)影響函數(shù)在translation unit(可以簡(jiǎn)單理解為C源碼文件)內(nèi)的編譯行為,只要超出了這個(gè)范圍inline屬性就沒(méi)有任何作用了。所以inline關(guān)鍵字不應(yīng)該出現(xiàn)在函數(shù)聲明中,沒(méi)有任何作用不說(shuō),有時(shí)還可能造成編譯錯(cuò)誤(在包含了sys/compiler.h
2、的情況下,聲明中出現(xiàn)inline關(guān)鍵字的部分通常無(wú)法編譯通過(guò)); inline關(guān)鍵字僅僅是建議編譯器做內(nèi)聯(lián)展開(kāi)處理,而不是強(qiáng)制。在gcc編譯器中,如果編譯優(yōu)化設(shè)置為-O0,即使是inline函數(shù)也不會(huì)被內(nèi)聯(lián)展開(kāi),除非設(shè)置了強(qiáng)制內(nèi)聯(lián)(__attribute__((always_inline)))屬性。 1. GCC的inline gcc對(duì)C語(yǔ)言的inline做了自己的擴(kuò)展,其行為與C99標(biāo)準(zhǔn)中的inline有較大的不同。 1.1. static inline GCC的static inline定義很容易理解:你可以把它認(rèn)為是一個(gè)static的函數(shù),加上了inline的屬性。這
3、個(gè)函數(shù)大部分表現(xiàn)和普通的static函數(shù)一樣,只不過(guò)在調(diào)用這種函數(shù)的時(shí)候,gcc會(huì)在其調(diào)用處將其匯編碼展開(kāi)編譯而不為這個(gè)函數(shù)生成獨(dú)立的匯編碼。除了以下幾種情況外: 函數(shù)的地址被使用的時(shí)候。如通過(guò)函數(shù)指針對(duì)函數(shù)進(jìn)行了間接調(diào)用。這種情況下就不得不為static inline函數(shù)生成獨(dú)立的匯編碼,否則它沒(méi)有自己的地址。 其他一些無(wú)法展開(kāi)的情況,比如函數(shù)本身有遞歸調(diào)用自身的行為等。 static inline函數(shù)和static函數(shù)一樣,其定義的范圍是local的,即可以在程序內(nèi)有多個(gè)同名的定義(只要不位于同一個(gè)文件內(nèi)即可)。 注意:gcc的static inline的表現(xiàn)行為和C99標(biāo)
4、準(zhǔn)的static inline是一致的。所以這種定義可以放心使用而沒(méi)有兼容性問(wèn)題。 要點(diǎn): gcc的static inline相對(duì)于static函數(shù)來(lái)說(shuō)只是在調(diào)用時(shí)建議編譯器進(jìn)行內(nèi)聯(lián)展開(kāi); gcc不會(huì)特意為static inline函數(shù)生成獨(dú)立的匯編碼,除非出現(xiàn)了必須生成不可的情況(如通過(guò)函數(shù)指針調(diào)用和遞歸調(diào)用); gcc的static inline函數(shù)僅能作用于文件范圍內(nèi)。 1.2. inline 相對(duì)于C99的inline來(lái)說(shuō),GCC的inline更容易理解:可以認(rèn)為它是一個(gè)普通全局函數(shù)加上了inline的屬性。即在其定義所在文件內(nèi),它的表現(xiàn)和static inline一致:在
5、能展開(kāi)的時(shí)候會(huì)被內(nèi)聯(lián)展開(kāi)編譯。但是為了能夠在文件外調(diào)用它,gcc一定會(huì)為它生成一份獨(dú)立的匯編碼,以便在外部進(jìn)行調(diào)用。即從文件外部看來(lái),它和一個(gè)普通的extern的函數(shù)無(wú)異。舉個(gè)例子: foo.c: /* 這里定義了一個(gè)inline的函數(shù)foo() */ inline foo() { 編譯器會(huì)像非inline函數(shù)一樣為foo()生成獨(dú)立的匯編碼 } void func1() { foo(); 同文件內(nèi)foo()可能被編譯器內(nèi)聯(lián)展開(kāi)編譯而不是直接call上面生成的匯編碼 } 而在另一個(gè)文件里調(diào)用foo()的時(shí)候,則直接call的是上面文件內(nèi)生成的匯編碼: bar.c: extern foo()
6、; 聲明foo(),注意不能在聲明內(nèi)帶inline關(guān)鍵字 void func2() { foo(); 這里就是直接call在foo.c內(nèi)為foo()函數(shù)生成的匯編碼了 雖然gcc的inline函數(shù)的行為很好理解,但是它和C99的inline是有很大差別的。請(qǐng)注意看后面對(duì)C99 inline的描述(第 2.2 節(jié) “inline”),以及如何以兼顧GCC和C99的方式使用inline函數(shù)。 要點(diǎn): gcc的inline函數(shù)相對(duì)于普通extern函數(shù)來(lái)說(shuō)只是在同一個(gè)文件內(nèi)調(diào)用時(shí)建議編譯器進(jìn)行內(nèi)聯(lián)展開(kāi); gcc一定會(huì)為inline函數(shù)生成一份獨(dú)立的匯編碼,以便其在本文件之外被調(diào)用。在別的文件
7、內(nèi)看來(lái),這個(gè)inline函數(shù)和普通的extern函數(shù)無(wú)異; gcc的inline函數(shù)是全局性的:在文件內(nèi)可以作為一個(gè)內(nèi)聯(lián)函數(shù)被內(nèi)聯(lián)展開(kāi),而在文件外可以調(diào)用它。 1.3. extern inline GCC的static inline和inline都很好理解:看起來(lái)都像是對(duì)普通函數(shù)添加了可內(nèi)聯(lián)的屬性。但是這個(gè)extern inline就千萬(wàn)不能想當(dāng)然地理解成就是一個(gè)extern的函數(shù)+inline屬性了。實(shí)際上gcc的extern inline十分古怪:一個(gè)extern inline的函數(shù)只會(huì)被內(nèi)聯(lián)進(jìn)去,而絕對(duì)不會(huì)生成獨(dú)立的匯編碼!即使是通過(guò)指針應(yīng)用或者是遞歸調(diào)用也不會(huì)讓編譯器為它生成匯
8、編碼,在這種時(shí)候?qū)Υ撕瘮?shù)的調(diào)用會(huì)被處理成一個(gè)外部引用。另外,extern inline的函數(shù)允許和外部函數(shù)重名,即在存在一個(gè)外部定義的全局庫(kù)函數(shù)的情況下,再定義一個(gè)同名的extern inline函數(shù)也是合法的。以下用例子具體說(shuō)明一下extern inline的特點(diǎn): foo.c: extern inline int foo(int a) { return (-a); } void func1() { ...; a = foo(a); ① p_foo = foo; ② b = p_foo(b); ③ } 在這個(gè)
9、文件內(nèi),gcc不會(huì)生成foo函數(shù)的匯編碼。在func1中的調(diào)用點(diǎn)①,編譯器會(huì)將上面定義的foo函數(shù)在這里內(nèi)聯(lián)展開(kāi)編譯,其表現(xiàn)類(lèi)似于普通inline函數(shù)。因?yàn)檫@樣的調(diào)用是能夠進(jìn)行內(nèi)聯(lián)處理的。而在②處,引用了foo函數(shù)的地址。但是注意:編譯器是絕對(duì)不會(huì)為extern inline函數(shù)生成獨(dú)立匯編碼的!所以在這種非要個(gè)函數(shù)地址不可的情況下,編譯器不得不將其處理為外部引用,在鏈接的時(shí)候鏈接到外部的foo函數(shù)去(填寫(xiě)外部函數(shù)的地址)。這時(shí)如果外部沒(méi)有再定義全局的foo函數(shù)的話(huà)就會(huì)在鏈接時(shí)產(chǎn)生foo函數(shù)未定義的錯(cuò)誤。 假設(shè)在另一個(gè)文件里面也定義了一個(gè)全局函數(shù)foo: foo2.c: int
10、foo(int a) { return (a); } 那么在上面那個(gè)例子里面,后面一個(gè)對(duì)foo函數(shù)地址的引用就會(huì)在鏈接時(shí)被指到這個(gè) foo2.c中定義的foo函數(shù)去。也就是說(shuō):①調(diào)用foo函數(shù)的結(jié)果是a=-a,因?yàn)槠鋬?nèi)聯(lián)了foo.c內(nèi)的foo函數(shù);而③調(diào)用的結(jié)果則是b=b,因?yàn)槠鋵?shí)際上調(diào)用的是foo2.c里面的foo函數(shù)! extern inline的用法很奇怪也很少見(jiàn),但是還是有其實(shí)用價(jià)值的。第一:它可以表現(xiàn)得像宏一樣,可以在文件內(nèi)用extern inline版本的定義取代外部定義的庫(kù)函數(shù)(前提是文件內(nèi)對(duì)其的調(diào)用不能出現(xiàn)無(wú)法內(nèi)聯(lián)的情況); 第二:它可以讓一個(gè)庫(kù)函數(shù)在能
11、夠被內(nèi)聯(lián)的時(shí)候盡量被內(nèi)聯(lián)使用。舉個(gè)例子: 在一個(gè)庫(kù)函數(shù)的c文件內(nèi),定義一個(gè)普通版本的庫(kù)函數(shù)libfunc: lib.c: void libfunc() { ...; } 然后再在其頭文件內(nèi),定義(注意不是聲明!) 一個(gè)實(shí)現(xiàn)相同的exterin inline的版本: lib.h: extern inline libfunc() { ...; } 那么在別的文件要使用這個(gè)庫(kù)函數(shù)的時(shí)候,只要include了lib.h,在能內(nèi)聯(lián)展開(kāi)的地方,編譯器都會(huì)使用頭文件內(nèi)extern inline的版本來(lái)展開(kāi)。而在無(wú)法展開(kāi)的時(shí)候(函數(shù)指針引用等情況),
12、編譯器就會(huì)引用lib.c中的那個(gè)獨(dú)立編譯的普通版本。即看起來(lái)似乎是個(gè)可以在外部被內(nèi)聯(lián)的函數(shù)一樣,所以這應(yīng)該是gcc的extern inline意義的由來(lái)。 但是注意這樣的使用是有代價(jià)的:c文件中的全局函數(shù)的實(shí)現(xiàn)必須和頭文件內(nèi) extern inline版本的實(shí)現(xiàn)完全相同。否則就會(huì)出現(xiàn)前面所舉例子中直接內(nèi)聯(lián)和間接調(diào)用時(shí)函數(shù)表現(xiàn)不一致的問(wèn)題。 gcc的extern inline函數(shù)的用法相當(dāng)奇怪,使用的范圍也非常狹窄:幾乎沒(méi)有什么情況會(huì)需要用它。 在C99中,也沒(méi)有關(guān)于extern inline這樣的描述,所以不建議大家使用extern inline,除非你明確理解了這種用法的意義并且有充
13、足的理由使用它! 要點(diǎn): gcc絕對(duì)不會(huì)為extern inline的函數(shù)生成獨(dú)立匯編碼 ;extern inline函數(shù)允許和全局函數(shù)重名,可以在文件范圍內(nèi)替代外部定義的全局函數(shù) ;extern inline函數(shù)的應(yīng)用范圍十分狹窄,而且行為比較奇怪,不建議使用 2. C99的inline 以下主要描述C99的inline與Gcc不同的部分。對(duì)于相同的部分請(qǐng)參考GCC inline的說(shuō)明。 2.1. static inline 同GCC的static inline(第 1.1 節(jié) “static inline”)。 2.2. inline C99的inline的使用
14、相當(dāng)令人費(fèi)解。當(dāng)一個(gè)定義為inline的函數(shù)沒(méi)有被聲明為extern的時(shí)候,其表現(xiàn)有點(diǎn)類(lèi)似于gcc中extern inline那樣(C99里面這段描述有點(diǎn)晦澀,原文如下): If all of the file scope declarations for a function in a translation unit include the inline function specifier without extern, then the definition in that translation unit is an inline definition. An inline de
15、finition does not provide an external definition for the function, and does not forbid an external definition in another translation unit. An inline definition provides an alternative to an external definition, which a translator may use to implement any call to the function in the same translation
16、unit. It is unspecified whether a call to the function uses the inline definition or the external definition. 即如果一個(gè)inline函數(shù)在文件范圍內(nèi)沒(méi)有被聲明為extern的話(huà),這個(gè)函數(shù)在文件內(nèi)的表現(xiàn)就和gcc的extern inline相似:在本文件內(nèi)調(diào)用時(shí)允許編譯器使用本文件內(nèi)定義的這個(gè)內(nèi)聯(lián)版本,但同時(shí)也允許外部存在同名的全局函數(shù)。只是比較奇怪的是C99居然沒(méi)有指定編譯器是否必須在本文件內(nèi)使用這個(gè)inline的版本而是讓編譯器廠(chǎng)家自己來(lái)決定,相當(dāng)模糊的定義。 如果在文件內(nèi)把
17、這個(gè)inline函數(shù)聲明為extern,則這個(gè)inline函數(shù)的表現(xiàn)就和gcc的inline一致了:這個(gè)函數(shù)即成為一個(gè)“external definition”(可以簡(jiǎn)單理解為全局函數(shù)):可以在外部被調(diào)用,并且在程序內(nèi)僅能存在一個(gè)這樣名字的定義。 下面舉例說(shuō)明C99中inline的特性: inline double fahr(double t) { return (9.0 * t) / 5.0 + 32.0; } inline double cels(double t) { return (5.0 * (t - 32.0)) / 9.0; } e
18、xtern double fahr(double); ① double convert(int is_fahr, double temp) { return is_fahr ? cels(temp) : fahr(temp); ② } 在上面這個(gè)例子里,函數(shù)fahr是個(gè)全局函數(shù):因?yàn)樵冖偬帉ahr聲明為extern,因此在②處調(diào)用fahr的時(shí)候使用的一定是這個(gè)文件內(nèi)所定義的版本(只不過(guò)編譯器可以將這里的調(diào)用進(jìn)行內(nèi)聯(lián)展開(kāi))。在文件外部也可以調(diào)用這個(gè)函數(shù)(說(shuō)明像 gcc的inline一樣,編譯器在這種情況下會(huì)為fahr生成獨(dú)立的匯編碼)。 而cels函數(shù)因?yàn)闆](méi)有
19、在文件范圍內(nèi)被聲明為extern,因此它就是前面所說(shuō)的 “inline definition”,這時(shí)候它實(shí)際上僅能作用于本文件范圍(就像一個(gè)static的函數(shù)一樣),外部也可能存在一個(gè)名字也為cels的同名全局函數(shù)。在②處調(diào)用cels的時(shí)候編譯器可能選擇用本文件內(nèi)的inline版本,也有可能跑去調(diào)用外部定義的cels函數(shù)(C99沒(méi)有規(guī)定此時(shí)的行為,不過(guò)編譯器肯定都會(huì)盡量使用文件內(nèi)定義的inline版本,要不然inline函數(shù)就沒(méi)有存在的意義了)。從這里的表現(xiàn)上看C99中未被聲明為extern的 inline函數(shù)已經(jīng)和gcc的extern inline十分相似了:本文件內(nèi)的inline函數(shù)可以作
20、為外部庫(kù)函數(shù)的替代。 C99標(biāo)準(zhǔn)中的inline函數(shù)行為定義的比較模糊,并且inline函數(shù)有沒(méi)有在文件范圍內(nèi)被聲明為extern的其表現(xiàn)有本質(zhì)不同。如果和gcc的inline函數(shù)比較的話(huà),一個(gè)被聲明為extern的inline函數(shù)基本等價(jià)于 GCC的普通inline函數(shù);而一個(gè)沒(méi)有被聲明為extern的inline函數(shù)基本等價(jià)于GCC的extern inline函數(shù)。 因?yàn)镃99的inline函數(shù)如此古怪,所以在使用的時(shí)候,建議為所有的inline函數(shù)都在頭文件中創(chuàng)建extern的聲明: foo.h: extern foo(); 而在定義inline函數(shù)的c文件內(nèi)include這個(gè)頭文件: foo.c: #include "foo.h" inline void foo() { ...; } 這樣無(wú)論是用gcc的inline規(guī)則還是C99的,都能得到完全相同的結(jié)果:foo函數(shù)會(huì)在foo.c文件內(nèi)被內(nèi)聯(lián)使用,而在外部又可以像普通全局函數(shù)一樣直接調(diào)用。 7 / 7
- 溫馨提示:
1: 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
2: 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶(hù)所有。
3.本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
5. 裝配圖網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶(hù)上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶(hù)上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶(hù)因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 市教育局冬季運(yùn)動(dòng)會(huì)安全工作預(yù)案
- 2024年秋季《思想道德與法治》大作業(yè)及答案3套試卷
- 2024年教師年度考核表個(gè)人工作總結(jié)(可編輯)
- 2024年xx村兩委涉案資金退還保證書(shū)
- 2024年憲法宣傳周活動(dòng)總結(jié)+在機(jī)關(guān)“弘揚(yáng)憲法精神推動(dòng)發(fā)改工作高質(zhì)量發(fā)展”專(zhuān)題宣講報(bào)告會(huì)上的講話(huà)
- 2024年XX村合作社年報(bào)總結(jié)
- 2024-2025年秋季第一學(xué)期初中歷史上冊(cè)教研組工作總結(jié)
- 2024年小學(xué)高級(jí)教師年終工作總結(jié)匯報(bào)
- 2024-2025年秋季第一學(xué)期初中物理上冊(cè)教研組工作總結(jié)
- 2024年xx鎮(zhèn)交通年度總結(jié)
- 2024-2025年秋季第一學(xué)期小學(xué)語(yǔ)文教師工作總結(jié)
- 2024年XX村陳規(guī)陋習(xí)整治報(bào)告
- 2025年學(xué)校元旦迎新盛典活動(dòng)策劃方案
- 2024年學(xué)校周邊安全隱患自查報(bào)告
- 2024年XX鎮(zhèn)農(nóng)村規(guī)劃管控述職報(bào)告