2013-06-12 154 views
2

這是從Linux內核源的摘錄。什麼是stem##用法?在C看到首次C中##是什麼意思?

#define __pcpu_size_call_return(stem, variable)       \ 
({  typeof(variable) pscr_ret__;         \ 
    __verify_pcpu_ptr(&(variable));         \ 
    switch(sizeof(variable)) {          \ 
    case 1: pscr_ret__ = stem##1(variable);break;     \ 
    case 2: pscr_ret__ = stem##2(variable);break;     \ 
    case 4: pscr_ret__ = stem##4(variable);break;     \ 
    case 8: pscr_ret__ = stem##8(variable);break;     \ 
    default:              \ 
      __bad_size_call_parameter();break;      \ 
    }                \ 
    pscr_ret__;              \ 
}) 
+4

基本的預處理器功能,如'##'操作符,你可以在任何關於C的書中閱讀。這總是一個好主意。這個地方主要是針對你在閱讀這本書之後可能還有的問題。 – AnT

+2

另外,如果你想學習正確的,可讀的標準C編程,Linux內核可能是你應該去看的最後一個地方...... – Lundin

+0

如果你問,請選擇一個更合適的問題標題。通常這是解決方案的第一步。 –

回答

6

##運算符是一種預處理器操作,它將一些令牌粘合在一起形成一個令牌單一

所以說你想調用基於一個共同的前綴兩種功能,每次路過一個參數,並允許它被改變。

不能使用:

#define CallBoth(pref,arg) \ 
{ \ 
    arg = pref A (arg); \ 
    arg = pref B (arg); \ 
} 

因爲取代prefA(或B)將不同令牌。同樣,您不能使用:

#define CallBoth(pref,arg) \ 
{ \ 
    arg = prefA (arg); \ 
    arg = prefB (arg); \ 
} 

因爲沒有prefAprefB替代會發生。

爲此,可以使用:

#define CallBoth(pref,arg) \ 
    { \ 
     arg = pref##A(arg); \ 
     arg = pref##B(arg); \ 
    }  

和取代prefA(或B)被連接到一個單一令牌。這樣一來,如果你輸入:

CallBoth(xyzzy,intVar); 

將被翻譯成:

{ 
    intVar = xyzzyA(intVar); 
    intVar = xyzzyB(intVar); 
} 

如果沒有這項功能,也沒有辦法與代表函數名的單個令牌結束。


正如文件中註釋所聲明你參考:

/*分支功能的功能分成一組函數,它們要求的不同尺寸的標處理的對象。 */

因此,取決於變量的大小被提供給宏,它將調用之一:

stem1(variable) 
stem2(variable) 
stem4(variable) 
stem8(variable) 

其中stemvariable被作爲參數給宏提供。或者如果沒有這些尺寸是相關的,它將呼叫__bad_size_call_parameter()

所以,一個電話:

char char_var; 
__pcpu_size_call_return(xyzzy,char_var) 

將導致一個電話:

xyzzy1(char_var): 

int int_var; 
__pcpu_size_call_return(xyzzy,int_var) 

將導致一個電話:

xyzzy4(int_var) 

其中sizeof(int) == 4

+1

我認爲'#'是「串化」,'##'是「令牌粘貼」? –

+0

@保羅,我想你可能是對的。實際上,這個標準只是把它們叫做'#'和'##'操作符,所以我現在就去做。 – paxdiablo

+0

非常感謝@paxdiablo這樣詳細的回答:) –

9

預處理操作者##提供了一種方法宏膨脹期間來連接的實際參數。如果在替換文本的參數是鄰近##,該參數通過實際的參數,所述##和周圍的空白替換被去除,並且將結果重新掃描。例如,宏粘貼會將其兩個參數:

#define paste(front, back) front ## back 

所以paste(name, 1)創建令牌name1