我在《c和指標》閱讀筆記(4)一文中詳細介紹了語句
、表示式
、操作符
之間的關係,在c語言中,語句是由表示式和(或)分號組成;表示式是由識別符號或操作符組成。本文再深入一步,介紹一種更複雜一點兒的用法:復合語句作為表示式
,然後引出乙個常用的編碼技巧。
在gnu c中,將復合語句通過小括號括起來後,可以當做表示式。這樣的方式可使表示式完成更複雜的邏輯:如迴圈、分支、使用區域性變數。
#define container_of(ptr, type, member) ()
container_of巨集的作用是由結構體成員的位址來獲取結構體的首位址
。暫時不關注巨集的具體內容(先賣個關子),僅看其輪廓,可以發現#define container_of(ptr, type, member) ({})
,本文中將({})
稱為復合語句表示式
。既然是表示式,那表示式的值又是什麼呢?
/*
* ()
* ()
* * 整個復合語句表示式的值為expressionn的值
*/
所以,container_of 復合語句表示式的值 是(type *)( (char *)__mptr - offsetof(type,member) );
的結果。
搞清楚了整體輪廓,接下來再講解細節。
/*
/usr/lib/gcc/x86_64-linux-gnu/7/include/stddef.h:417
#define offsetof(type, member) __builtin_offsetof (type, member)
*/// offsetof的本質邏輯如下:
//#define offsetof(type, member) (size_t)&(((type*)0)->member)
// 獲取結構體成員在結構體中的偏移
// ((type*)0), 將0強轉為指向type型別的指標
// &(((type*)0)->member), 獲取成員member的位址;由於((type*)0)的位址為0, 那麼member的位址即為其在結構體中的偏移
// 由結構體成員的位址來獲取結構體的首位址
#define container_of(ptr, type, member) ()
// ptr 表示結構體成員的位址
// type 表示結構體型別
// member 表示成員名, ptr和member代表相同成員
// typeof( ((type *)0)->member ) 獲取member的資料型別
// typeof( ((type *)0)->member ) *__mptr 定義乙個member資料型別的指標
// const typeof( ((type *)0)->member ) *__mptr = (ptr); 儲存ptr位址
// ( (char *)__mptr - offsetof(type,member) ) ptr的位址 減去member的偏移量, 即得到結構體的位址
// (type *)( (char *)__mptr - offsetof(type,member) ) 再將位址強轉為結構體指標
注意,如果使用g++ std=c++11編譯,需要將typeof改為decltype
。當然,使用gcc編譯時沒有問題。
#include
#include
#include
#include
// include offsetof(type, member)
typedef
struct
com_queue_t;
typedef
struct _sample_bgra_queue_s
sample_bgra_queue_t;
void
test_offset()
intmain
(int argc,
char
** ar**)
參考: 復合lambda表示式
複習 public static void main string args 用lambda表示式 因為編譯器會自動根據 上下文推測出資料型別因此 collections.sort list,first,second first.getcolor compareto second.getcolor ...
1 2復合表示式與if語句書寫技巧
復合表示式由常量 變數 函式和運算子組成書寫應注意 1 不要過於複雜 如 x y z a i c 2 不要與數學表示式混淆 如 if x3 運算子優先順序和結合性直對結果的影響 4 表示式中有些部分可能沒參加運算 如 int a 1,b 2 if acout 輸出結果為1 aif語句書寫技巧與注意問...
正規表示式高階用法
1.獲取匹配 獲取這個匹配結果 可以使用 num 代替這個匹配的結果,可以用來實現替換功能。獲取這個匹配結果 pattern 2.非獲取匹配 和獲取匹配相反,不獲取匹配結果 pattern 以下四種預查方式都是非獲取匹配 1.正向肯定預查 與它前面的匹配表示式銜接,並通過它自己的表示式篩選前面的匹配...