原文链接地址: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,以下是範例:
- #define COMMAND(NAME) { #NAME, NAME ## _command }
- struct
command commands[] = {
- COMMAND (quit),
- COMMAND (help),
- //...
- };
經過C preprocessor處理後,會展開如下:
- struct
command commands[] = {
- { “quit”, quit_command },
- { “help”, help_command },
- //...
- };
其中#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(其中省略了不相關的幾行程式碼):
- #define PIXOP2(OPNAME, OP) /
- static void OPNAME ## _pixels2_c(uint8_t *block, const uint8_t *pixels, int line_size, int h){/
- //...
- OP(*((uint16_t*)(block)), AV_RN16(pixels));/
- //...
- }/
- static void OPNAME ## _pixels4_c(uint8_t *block, const uint8_t *pixels, int line_size, int h){/
- //...
- OP(*((uint32_t*)(block)), AV_RN32(pixels));/
- //...
- }/
- //...
在下面則使用這段code的方式:
- #define op_avg(a, b) a = rnd_avg32(a, b)
- #define op_put(a, b) a = b
- PIXOP2(avg, op_avg)
- PIXOP2(put,op_put)
- #undef op_avg
- #undef op_put
- //from ffmpeg0.5, libavcodec/dsputil.c
使用gcc -E來展開preprocessor動作後,Line 1261和1262,呼叫PIXOP2的macro,就會自動產生新的function definition:
- static void avg_pixels2_c(uint8_t *block, const uint8_t pixels, int line_size, int h){
- ((uint16_t*)(block )) = rnd_avg32(*((uint16_t*)(block )), AV_RN16(pixels ));
- }
- static void avg_pixels4_c(uint8_t *block, const uint8_t pixels, int line_size, int h){
- ((uint32_t*)(block )) = rnd_avg32(*((uint32_t*)(block )), AV_RN32(pixels ));
- }
- static void put_pixels2_c(uint8_t *block, const uint8_t pixels, int line_size, int h){
- ((uint16_t*)(block )) = AV_RN16(pixels );
- }
- static void put_pixels4_c(uint8_t *block, const uint8_t pixels, int line_size, int h){
- ((uint32_t*)(block )) = AV_RN32(pixels );
- }
又學到一招,這code還真簡潔明瞭,不需要重複寫很多同質性的function definition。
有關C preprocessor的token concatenation介紹請參考這裡 。