與 巨集定義的作用

2021-06-25 16:43:01 字數 2830 閱讀 1142

核心中有很多的巨集定義,在巨集定義define中經常看到兩個字串##和#,這裡把它的用法做一下說明: 

##是乙個連線符號,用於把引數連在一起         例如: 

> #define  foo(arg)   my##arg         則 

> foo(abc)         相當於   myabc      

#是「字串化」的意思。出現在巨集定義中的#是把跟在後面的引數轉換成乙個字串         例如: 

> #define strcpy(dst, src)   strcpy(dst, #src)         則 

> strcpy(buff, abc)         相當於   strcpy(buff, "abc") 

另外,如果##後的引數本身也是乙個巨集的話,##會阻止這個巨集的展開 。  

#define strcpy(a, b)    strcpy(a ## _p, #b)     int main()      

/  tell you about ## in common text 

關於記號貼上操作符(token paste operator): ##  

1. 簡單的說,「##」是一種分隔連線方式,它的作用是先分隔,然後進行強制連線。  

其中,分隔的作用類似於空格。我們知道在普通的巨集定義中,預處理器一般把空格    解釋成分段標誌,對於每一段和前面比較,相同的就被替換。但是這樣做的結果是,    被替換段之間存在一些空格。如果我們不希望出現這些空格,就可以通過新增一些    ##來替代空格。  

另外一些分隔標誌是,包括操作符,比如 +, -, *, /, [,], ...,所以儘管下面的    巨集定義沒有空格,但是依然表達有意義的定義: define add(a, b)  a+b 

而其強制連線的作用是,去掉和前面的字串之間的空格,而把兩者連線起來。  

2. 舉列 -- 試比較下述幾個巨集定義的區別 

#define a1(name, type)  type name_##type##_type 或    #define a2(name, type)  type name##_##type##_type  

a1(a1, int);  /* 等價於: int name_int_type; */    a2(a1, int);  /* 等價於: int a1_int_type;   */ 

解釋: 

1) 在第乙個巨集定義中,"name"和第乙個"_"之間,以及第2個"_"和第二個    "type"之間沒有被分隔,所以預處理器會把name_##type##_type解釋成3段:    「name_」、「type」、以及「_type」,這中間只有「type」是在巨集前面出現過     的,所以它可以被巨集替換。 

2) 而在第二個巨集定義中,「name」和第乙個「_」之間也被分隔了,所以    預處理器會把name##_##type##_type解釋成4段:「name」、「_」、「type」    以及「_type」,這其間,就有兩個可以被巨集替換了。  

3) a1和a2的定義也可以如下: 

#define a1(name, type)  type name_  ##type ##_type   

<##前面隨意加上一些空格》            #define a2(name, type)  type name ##_ ##type ##_type 

結果是## 會把前面的空格去掉完成強連線,得到和上面結果相同的巨集定義  

3. 其他相關 -- 單獨的乙個 # 

至於單獨乙個#,則表示 對這個變數替換後,再加雙引號引起來。比如  

#define  __stringify_1(x)   #x 那麼 

__stringify_1(linux)   <==>  "linux"  

所以,對於module_device_table  

1) #define module_device_table(type,name)                                      module_generic_table(type##_device,name) 

2) #define module_generic_table(gtype,name)                                    extern const struct gtype##_id __mod_##gtype##_table                   __attribute__ ((unused, alias(__stringify(name))))  

得到   

module_device_table(usb, products)   

/*notes: struct usb_device_id products; */  <==> module_generic_table(usb_device,products) 

<==> extern const struct usb_device_id __mod_usb_device_table                   __attribute__ ((unused, alias("products")))     

注意到alias attribute需要乙個雙引號,所以在這裡使用了__stringify(name)來 

給name加上雙引號。另外,還注意到乙個外部變數"__mod_usb_device_table"被alias 到了本驅動專用的由使用者自定義的變數products4. 分析方法和驗證方式 -- 編寫乙個簡單的c程式 

用巨集定義乙個變數,同時用直接方式定義乙個相同的變數,編譯報告重複定義;    用巨集定義乙個變數,直接使用該巨集定義的變數名稱,編譯通過且執行結果正確;    使用printf列印字串資料。printf("token macro is %s", __stringify_1(a1));

巨集定義中 號的作用

1.的作用是,對這個變數替換後,再加雙引號引起來,例如 define a a a,那麼有a 10 10 對空格的處理 a.忽略傳入引數名前面和後面的空格。如 str example1 abc 將會被擴充套件成 str abc b.當傳入引數名間存在空格時,編譯器將會自動連線各個子字串,用每個子字串中...

CHECK 巨集定義的作用 caffe

個人在學習caffe原始碼檔案時遇到了check eq函式,不理解什麼含義,經過上下文理解,明白了其中含義。check eq x,y x y eq即equation,意為 等於 函式判斷是否x等於y,當x y時,函式列印出x y。check ne x,y x y ne即not equation,意為...

C語言 預處理作用與巨集定義

1.程式的預處理過程就是將預處理指令 可以簡單理解為 開頭的正確指令 轉換為實際 中的內容 替換 2.include,這裡是預處理指令,包含標頭檔案的操作,將所包含標頭檔案的指令替代 3.如果標頭檔案中包含了其他標頭檔案,也需要將標頭檔案展開包含1.define 新的標識 舊的標識 注意這裡加不加分...