C6000系列DSP的行內函數
在c中,為了解決一些頻繁呼叫的小函式大量消耗棧空間或是叫棧記憶體的問題,特別的引入了inline修飾符,表示為行內函數數。棧空間就是指放置程式的區域性資料也就是函式內資料的記憶體空間,在系統下,棧空間是有限的,假如頻繁大量的使用就會造成因棧空間不足所造成的程式出錯的問題,函式的死迴圈遞迴呼叫的最終結果就是導致棧記憶體空間枯竭。
下面我們來看一個例子
#include <stdio.h>
inline char* dbtest(int a); //函式原形宣告為inline即:內聯涵數
int main()
{
int i = 0;
for (i=1;i<=10;i )
{
printf("%d is %s/n",i,dbtest(i));
}
return 0;
}
char* dbtest(int a)//這裡不用再次inline,當然加上inline也是不會出錯的
{
return (a%2>0)?"奇":"偶";
}
上面的例子就是標準的行內函數的用法,使用inline修飾帶來的好處我們表面看不出來,其實在內部的工作就是在每個for迴圈的內部任何呼叫 dbtest(i)的地方都換成了(i%2>0)?"奇":"偶"這樣就避免了頻繁呼叫函式對棧記憶體重複開闢所帶來的消耗。
說到這裡很多人可能會問,既然inline這麼好,還不如把所謂的函式都宣告成inline,嗯,這個問題是要注意的,inline的使用是有所限制的,inline只適合涵數體內程式碼簡單的涵數使用,不能包含複雜的結構控制語句例如while switch,並且不能行內函數本身不能是直接遞迴函式(自己內部還呼叫自己的函式)。
說到這裡我們不得不說一下在c語言中廣泛被使用的#define語句,是的define的確也能夠做到inline的這些工作,但是define是會產生副作用的,尤其是不同型別引數所導致的錯誤,由此可見inline有更強的約束性和能夠讓編譯器檢查出更多錯誤的特性,在c 中是不推薦使用define的。
inline函式僅僅是一個建議,對編譯器的建議,所以最後能否真正內聯,看編譯器的意思,它如果認為你的函式不復雜,能在呼叫點展開,就會真正內聯,並不是說聲明瞭內聯就會內聯,你宣告內聯只是一個建議而已.
其次,因為行內函數要在呼叫點展開,所以編譯器必須隨處可見行內函數的定義,要不然,就成了非行內函數的呼叫了.所以,這要求你的每個呼叫了行內函數的檔案都出現了該行內函數的定義,因此,將行內函數放在標頭檔案裡實現是合適的,省卻你為每個檔案實現一次的麻煩.而你所以宣告跟定義要一致,其實是指,如果你在每個檔案裡都實現一次該行內函數的話,那麼,你最好保證每個定義都是一樣的,否則,將會引起未定義的行為,即是說,如果不是每個檔案裡的定義都一樣,那麼,編譯器展開的是哪一個,那要看具體的編譯器而定.所以,最好將行內函數定義放在標頭檔案中.
而類中的成員函式預設都是內聯的,如果你在類定義時就在類內給出函式,那當然最好.如果你在類中未給出成員函式定義,而你又想內聯該函式的話,那在類外要加上inline,否則就認為不是內聯的.而且剛說了,行內函數最好放在標頭檔案內,所以最好在類定義的標頭檔案裡把類的行內函數都實現了.
而你說的將宣告與實現分開,其實是不會編譯出錯的,反正我寫那麼多程式都沒試過.將宣告與定義分開的話,這樣的後果會帶來編譯器並不隨處可見該函式定義,所以,只能在你實現定義的那個檔案裡,將該函式看成內聯(如果可以內聯的話),在其它檔案,仍看成是普通函式.
在dsp中會見到這樣的用法static inline void CSL_init()
其中static是以前C的用法.目的是讓該關鍵字標識的函式只在本地檔案可見,同一個程式的其它檔案是不可見該函式的.換句話說,就算你其它檔案裡包含了同名同參數表的函式定義的話,也是不會引起函式重複定義的錯誤的.因為static是僅在當前檔案可見
extern inline表示該函式是已宣告過的了.由於函式本身可以宣告多次,所以extern對函式的影響僅僅把函式的隱藏屬性顯式化了.extern 對於非函式的物件是有用的,因為物件宣告時會帶來記憶體的分配,而用 extern就表示該物件已經宣告過了,不用再分配記憶體.