神奇的 ## 符號

原文鏈接地址:http://starryalley.homelinux.net/blog/index.php?/archives/1134-Token-Concatenation-in-C-preprocessor.html

Token Concatenation in C preprocessor

使用程式碼來介紹比較快:

     #define foo() bar

foo()baz

==> bar baz

not


==> barbaz



所以加上’##’的用法,就可以達成barbaz,以下是範例:


  1. #define COMMAND(NAME)  { #NAME, NAME ## _command }
      

  2. struct
     command commands[] = {  

  3.   COMMAND (quit),  
  4.   COMMAND (help),  
  5.   //...
      

  6. };  





經過C preprocessor處理後,會展開如下:




  1. struct
     command commands[] = {  

  2.   { “quit”, quit_command },  
  3.   { “help”, help_command },  
  4.   //...
      

  5. };  







其中#NAME是Stringification的功能,所以配合’##’ token concatenation,我們可以結合兩個param。




之前在trace ffmpeg source code,其中竟然找不到put_pixels4_c()這類 function的definition,ctags找不到,grep好久也沒有。原來就是利用了token concatenation來產生的function。

以下是 節錄ffmpeg 0.5 source 裡面的一段code,用了C preprocessor token concatenation(其中省略了不相關的幾行程式碼):

  1. #define PIXOP2(OPNAME, OP) /   
  2. static   void  OPNAME ## _pixels2_c(uint8_t *block,  const  uint8_t *pixels,  int  line_size,  int  h){/  
  3.   //...    
  4.   OP(*((uint16_t*)(block)), AV_RN16(pixels));/  
  5.   //...   
  6. }/  
  7. static   void  OPNAME ## _pixels4_c(uint8_t *block,  const  uint8_t *pixels,  int  line_size,  int  h){/  
  8.   //...   
  9.   OP(*((uint32_t*)(block)), AV_RN32(pixels));/  
  10.   //...   
  11. }/  
  12. //...   


在下面則使用這段code的方式:

  1. #define op_avg(a, b) a = rnd_avg32(a, b)   
  2. #define op_put(a, b) a = b   
  3. PIXOP2(avg, op_avg)  
  4. PIXOP2(put,op_put)  
  5. #undef op_avg   
  6. #undef op_put   
  7. //from ffmpeg0.5, libavcodec/dsputil.c   

使用gcc -E來展開preprocessor動作後,Line 1261和1262,呼叫PIXOP2的macro,就會自動產生新的function definition:

  1. static   void  avg_pixels2_c(uint8_t *block,  const  uint8_t pixels,  int  line_size,  int  h){  
  2.     ((uint16_t*)(block )) = rnd_avg32(*((uint16_t*)(block )), AV_RN16(pixels ));  
  3. }  
  4. static   void  avg_pixels4_c(uint8_t *block,  const  uint8_t pixels,  int  line_size,  int  h){  
  5.     ((uint32_t*)(block )) = rnd_avg32(*((uint32_t*)(block )), AV_RN32(pixels ));  
  6. }  
  7. static   void  put_pixels2_c(uint8_t *block,  const  uint8_t pixels,  int  line_size,  int  h){  
  8.     ((uint16_t*)(block )) = AV_RN16(pixels );  
  9. }  
  10. static   void  put_pixels4_c(uint8_t *block,  const  uint8_t pixels,  int  line_size,  int  h){  
  11.     ((uint32_t*)(block )) = AV_RN32(pixels );  
  12. }  

又學到一招,這code還真簡潔明瞭,不需要重複寫很多同質性的function definition。

有關C preprocessor的token concatenation介紹請參考這裡

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章