Tips of Linux C programming

1. 優雅地使用鏈表

        鏈表是編程中經常要用到的數據結構,結構體描述時分爲數據域和指針域,本沒有什麼好講。但有沒有想過教科書上的這種方式有什麼問題?通過這種方式定義和使用鏈表,對於不同的鏈表類型,都要定義各自的鏈表結構,繁瑣的很。linux kernel中鏈表的用法才應該是教科書中出現的。
        基本思想:在Linux內核鏈表中,不是在鏈表結構中包含數據,而是在數據結構中包含鏈表節點。
1) 鏈表定義:
struct list_head {
    struct list_head *next, *prev;
};
#define LIST_HEAD_INIT(name) { &(name), &(name) }

2) 鏈表使用者定義:

struct user_t {
    data domain;
    struct list_head node;
};
struct list_head g_user_list = LIST_HEAD_INIT(g_user_list);
3) 通過node定位user_t:
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
#define container_of(ptr, type, member) ({          
    const typeof(((type *)0)->member) * __mptr = (ptr); 
(type *)((char *)__mptr - offsetof(type, member)); })
struct user_t* next = container_of(&(g_user_list.next->node), struct user_t, node);

這裏用到了container_of,container_of又用到了offsetof。offsetof是通過將結構體起始地址強制對齊到0來計算出node和起始地址的偏移offset;而container_of在node地址基礎上減去offset得到user_t結構體的地址並返回user_t。

2. 高效地分支判斷
        寫程序不可避免的需要使用if/else,如何高效地進行分支判斷呢?使用likely/unlikely。
#define likely(x)       __builtin_expect(!!(x), 1)
#define unlikely(x)     __builtin_expect(!!(x), 0)
long __builtin_expect (long EXP, long C)
        __builtin_expect是一個GCC內置的函數,語義是表示EXP == C,返回值是表達式的值。這兩個宏定義是爲了提示編譯器正確地進行分支判斷的優化。
        優化的原理是:通過調整生成彙編代碼的順序,將經常發生的分支代碼放在cmp指令之後順序執行,將不經常發生的分支代碼通過jump指令跳過去,從而降低jump指令清空處理器流水線的影響。
3. 彙編實現的原子操作
__asm__ __volatile__(
                       "   lock       ;n"
                       "   addl %1,%0 ;n"
                       : "=m"  (my_var)   //output
                      : "ir"  (my_int), "m" (my_var)  //input
                      :       //modify  /* no clobber-list */
                      );
        這條彙編表示給my_var原子加my_int,lock前綴就是用來保證原子性的。
        Intel CPU有3種保證原子性的方式,lock前綴是其中之一,原理是通過鎖總線來阻止其它處理器操作相應的地址。
4. 0長度數組
        定義數組時,長度必須是一個編譯時確定的值,如果想使用運行時的值來確定數組的長度,可以使用0長度數組。
struct line {
       int length;
       char contents[0];
     };
struct line *thisline = (struct line *)malloc (sizeof (struct line) + this_length);
thisline->length = this_length;

只有GNU C才支持的特性,對於定義不確定長度的數組非常有用。

5. 三目運算的另類表達
        GNU 允許C 語言省略條件表達式中的表達式2省略, 此時表示表達式2與表達式1相同.例如
a = x ? : y;
等價於
a = x ? x : y;
但是如果 x 是一個表達式, 僅求值一次.
        也來分享一下你正在使用的tips吧!
參考文章:
http://www.ibm.com/developerworks/cn/linux/kernel/l-chain/index.html
http://kernelnewbies.org/FAQ/LikelyUnlikely
http://www.ibiblio.org/gferg/ldp/GCC-Inline-Assembly-HOWTO.html
http://gcc.gnu.org/onlinedocs/gcc/Zero-Length.html
http://zh.wikipedia.org/wiki/%E6%9D%A1%E4%BB%B6%E8%BF%90%E7%AE%97%E7%AC%A6
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章