利用宏定義的##完成函數模板的定義與調用
宏定義代碼段
#define DEFINE_LDST_DMA(_lname, _sname, _bits, _end) \
static inline uint##_bits##_t ld##_lname##_##_end##_dma(AddressSpace *as, \
dma_addr_t addr) \
{ \
uint##_bits##_t val; \
dma_memory_read(as, addr, &val, (_bits) / 8); \
return _end##_bits##_to_cpu(val); \
} \
static inline void st##_sname##_##_end##_dma(AddressSpace *as, \
dma_addr_t addr, \
uint##_bits##_t val) \
{ \
val = cpu_to_##_end##_bits(val); \
dma_memory_write(as, addr, &val, (_bits) / 8); \
}
調用宏定義不同的函數,以下代碼實際定義了12個返回類型、函數名、函數內部變量類型不同的函數
DEFINE_LDST_DMA(uw, w, 16, le);
DEFINE_LDST_DMA(l, l, 32, le);
DEFINE_LDST_DMA(q, q, 64, le);
DEFINE_LDST_DMA(uw, w, 16, be);
DEFINE_LDST_DMA(l, l, 32, be);
DEFINE_LDST_DMA(q, q, 64, be);
宏定義中的#與##的含義
在宏定義中#是“字符串化”的意思。出現在宏定義中的#是把跟在后面的參數轉換成一個字符串。
其作用是:將宏定義中的傳入參數名轉換成用一對雙引號括起來參數名字符串。其只能用於有傳入參數的宏定義中,且必須置於宏定義體中的參數名前
例如宏定義代碼
#define M(x) printf("result = %s",#x)
執行該宏定義
int a=1;
M(A);
實際結果為
result = A
宏定義中##是一種分隔連接方式,它的作用是先分隔,然后進行強制連接
例如
#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; */
解釋:
- 在第一個宏定義中,"name"和第一個""之間,以及第2個""和第二個"type"之間沒有被分隔,所以預處理器會把
name_##type##_type
解釋成3段:
“name_”、“type”、以及“_type”,這中間只有“type”是在宏前面出現過
的,所以它可以被宏替換。
- 而在第二個宏定義中,“name”和第一個“_”之間也被分隔了,所以
預處理器會把name##_##type##_type
解釋成4段:“name”、“_”、“type”
以及“_type”,這其間,就有兩個可以被宏替換了。
- A1和A2的定義也可以如下:
#define A1(name, type) type name_ ##type ##_type
<##前面隨意加上一些空格>
#define A2(name, type) type name ##_ ##type ##_type
結果是## 會把前面的空格去掉完成強連接,得到和上面結果相同的宏定義
如果##后的參數本身也是一個宏的話,##會阻止這個宏的展開,也就是只替換一次。
#define STRCPY(a, b) strcpy(a ## _p, #b)
int main()
{
char var1_p[20];
char var2_p[30];
/* 注意這里 */
STRCPY(STRCPY(var1,var2),var2);
/* 這里是否會展開為: strcpy(strcpy(var1_p,"var2")_p,"var2“)?
* 答案是否定的:
* 展開結果將是: strcpy(STRCPY(var1,var2)_p,"var2")
* ## 阻止了參數的宏展開!
* 如果宏定義里沒有用到 # 和 ##, 宏將會完全展開
*/
}
詳見參考:
http://blog.csdn.net/jiangjingui2011/article/details/6706967