天天看點

Linux中内聯函數,static inline Linux内聯函數

轉載: http://blog.csdn.net/buaaroid/article/details/7390415

asmlinkage/FASTCALL()/fastcall

這三個宏指定了函數參數的傳遞方式。asmlinkage修飾的函數,其參數通過堆棧傳遞。FASTCALL()/fastcall,此二者實際上是一樣的作用。在Intel i386架構中,它們所修飾的函數,其前三個參數分别通過通用寄存器EAX,ECX和EDX來傳遞。

它們定義于include/asm-i386/linkage.h:

#define asmlinkage CPP_ASMLINKAGE __attribute__((regparm(0)))

#define FASTCALL(x) x __attribute__((regparm(3)))

#define fastcall __attribute__((regparm(3)))

此處利用的是函數屬性regparm。

static inline内聯函數

内聯函數有些類似于宏。内聯函數的代碼會被直接嵌入在它被調用的地方,調用幾次就嵌入幾次,沒有使用call指令。這樣省去了函數調用時的一些額外開 銷,比如儲存和恢複函數傳回位址等,可以加快速度。不過調用次數多的話,會使可執行檔案變大,這樣會降低速度。相比起宏來說,核心開發者一般更喜歡使用内 聯函數。因為内聯函數沒有長度限制,格式限制。編譯器還可以檢查函數調用方式,以防止其被誤用。

static inline的内聯函數,一般情況下不會産生函數本身的代碼,而是全部被嵌入在被調用的地方。如果不加static,則表示該函數有可能會被其他編譯單元 所調用,是以一定會産生函數本身的代碼。是以加了static,一般可令可執行檔案變小。核心裡一般見不到隻用inline的情況,而都是使用 static inline。

有時候也可以見到static __inline__。gcc編譯參數“-ansi”或者“-std=c89”等會禁用一些關鍵字,比如“asm”,“inline”等。為了在這種情況 下使用内聯函數,gcc提供了“__inline__”關鍵字。不過核心使用的标準是gnu89,是以“inline”和“__inline__”在核心 中都可以使用。現在“inline”已經成了C99标準的關鍵字。gcc未來的預設标準也将變成基于C99的gnu99。是以現在寫核心代碼時,推薦使用 “inline”關鍵字,而不要用“__line__”。

Linux核心中的許多規範需要經過反複查找和閱讀才能發現其最終的意義和目的。本篇文章搜集并澄清C語言用法中幾個含糊不清,容易混淆的地方。

(1) asmlinkage

asmlinkage 告訴編譯器要使用局部堆棧來傳遞參數,而宏FASTCALL通知編譯程式使用通用寄存器來傳遞參數。

以下是來自 include/linux/linkage.h 的代碼(2.4.0):

#ifdef __cplusplus#define CPP_ASMLINKAGE extern "C"

#else

#define CPP_ASMLINKAGE

#endif

#if defined __i386__

#define asmlinkage CPP_ASMLINKAGE __attribute__((regparm(0)))

#elif defined __ia64__

#define asmlinkage CPP_ASMLINKAGE __attribute__((syscall_linkage))

#else

#define asmlinkage CPP_ASMLINKAGE

#endif

(2) UL

UL常被用在數值常數後,标明該常數為"unsigned long"類型,UL(L代表long)負責告訴編譯程式将這一數值當作long型數值來處理。是以,使用UL很有必要,它能夠保證特定體系結構内的資料 不會溢出其資料類型所規定的範圍。涉及很大的數或長的位掩碼時,使用UL有助于編寫出與體系結構無關的代碼。

Linux代碼中有這樣的例子,如:

include/linux/kernel.h

#define INT_MAX ((int)(~0U>>1))

#define INT_MIN (-INT_MAX - 1)

#define UINT_MAX (~0U)

#define LONG_MAX ((long)(~0UL>>1))

#define LONG_MIN (-LONG_MAX - 1)

#define ULONG_MAX (~0UL)

(3)inline

關鍵字inline表明要優化函數的可執行代碼,這可以通過将函數的代碼合并到調用程式的代碼中來實作。Linux核心使用的inline函數大多被定義為static 類型。一個"static inline"函數促使編譯程式嘗試着将其代碼插入到所有調用它的程式中。

這一合并能夠免除函數調用的任何開銷,#define語句也可以排除額外的函數調用。

另外,使用inline會增加二進制映像的大小,而這會降低通路CPU高速緩存的速度,是以不能在所有的函數定義中使用它。

(4)const 和 volatile

const不一定隻代表常數,有時它表示"隻讀"的意思。例如,"const int * x" 中x是一個指向const整數的指針,是以,可以修改指針,但不能修改這個整數;而在"int const * x"中,x卻是一個指向整數的const指針,因而這個整數可以改變,但指針x卻不能改變。

關鍵字volatile表明變量無需警告就可以被修改,它通知編譯程式每次使用該變量時都要重新加載其值,而不是存儲并通路一個副本。中斷處理,硬體寄存器,以及并發程序之間共享的變量都是被标記為volatile的典型例子.

include/asm-i386/spinlock.h

typedef struct{volatile unsigned int lock;#if SPINLOCK_DEBUGunsigned magic;#endif} spinlock_t;

完。