1引言
在C或C++
開發(fā)中,我們經(jīng)常會在代碼中使用一些宏來簡化編碼,提升可閱讀性。這里我總結(jié)了一些常用的、有趣的宏。
NAME2/UNIQUE_NAME
NAME2宏的實(shí)現(xiàn)如下,功能是將兩個字符連接成一個字符。對于UNIQUE_NAME
宏,則是在NAME2
的基礎(chǔ)上增加一個__LINE__
參數(shù),從而生成一個根據(jù)當(dāng)前調(diào)用處的行數(shù)生成一個以prefix
為前綴的字符。
#define __NAME2_HELPER(a, b) a ## b
#define NAME2(a, b) __NAME2_HELPER(a, b)
#define UNIQUE_NAME(prefix) NAME2(NAME2(prefix, _), __LINE__)
測試如下:
// int a1 = 5;
int NAME2(a, 1) = 5;
// NAME2(a, 1): 5 = 5
printf("NAME2(a, 1): %d = %d\n", a1, NAME2(a, 1));
// STR(NAME2(a, 1)): a1
printf("STR(NAME2(a, 1)): %s\n", STR(NAME2(a, 1)));
// STR(STR(NAME2(a, 1))): "a1"
printf("STR(STR(NAME2(a, 1))): %s\n", STR(STR(NAME2(a, 1))));
STR(ABCD): ABCD
printf("STR(ABCD): %s\n", STR(ABCD));
// int val_11 = 0;
int UNIQUE_NAME(val) = 0;
ARRAY_SIZE
ARRAY_SIZE為計算靜態(tài)數(shù)組的長度。IS_ARRAY
則是判斷參數(shù)的類型是否為數(shù)組,而非指針。定義如下:
#define ARRAY_SIZE(arr) (sizeof(arr)/sizeof(0[arr]))
# define _IS_SAME_TYPE(T1,T2) \
__builtin_types_compatible_p(__typeof__(T1), __typeof__(T2))
#define IS_ARRAY(A) !_IS_SAME_TYPE( (A), &(A)[0] )
測試如下:
uint8_t arr[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
/* 輸出
ARRAY_SIZE(arr): 10
index: 0: 0
index: 1: 1
index: 2: 2
index: 3: 3
index: 4: 4
index: 5: 5
index: 6: 6
index: 7: 7
index: 8: 8
index: 9: 9
*/
printf("ARRAY_SIZE(arr): %ld\n", ARRAY_SIZE(arr));
for (size_t i = 0; i < ARRAY_SIZE(arr); i++) {
printf(" index: %ld: %d\n", i, arr[i]);
}
int arr1[10];
int *ptr1 = arr1;
// arr1[10]: 1
printf("arr1[10]: %d\n", IS_ARRAY(arr1));
// val1: 0
printf("val1: %d\n", IS_ARRAY(ptr1));
FOREACH_ARRAY_ELEMENT
FOREACH_ARRAY_ELEMENT
為遍歷數(shù)組的每個元素,第三個參數(shù)為閉包,可以被宏內(nèi)部調(diào)用。
#define FOREACH_ARRAY_ELEMENT(arr, item_ptr, closure) \
do{ \
for (size_t i = 0; i < ARRAY_SIZE(arr); i++ ) { \
typeof(arr[0]) *item_ptr = arr + i; \
{closure} \
} \
}while(0)
測試如下:
/* 輸出:
A B C D E F G
*/
char char_list[7] = "abcdefg";
FOREACH_ARRAY_ELEMENT(char_list, p_ch, {
printf("%c ", *p_ch - 'a' + 'A');
});
ITEM_DEF_LIST/ITEM_DEF
ITEM_DEF_LIST/ITEM_DEF
為定義一系列相同的清單項(xiàng),如子項(xiàng)名與序號等,實(shí)現(xiàn)如下。
#define ITEM_DEF_LIST \
ITEM_DEF(a1, 1, 1) \
ITEM_DEF(a2, 2, 3) \
ITEM_DEF(a3, 3, 5) \
ITEM_DEF(a4, 4, 7) \
ITEM_DEF(a5, 5, 9)
typedef enum _item_n{
#define ITEM_DEF(name, idx, val) NAME2(item, name) = idx,
ITEM_DEF_LIST
#undef ITEM_DEF
}item_n;
typedef struct _item{
#define ITEM_DEF(name, idx, val) int name;
ITEM_DEF_LIST
#undef ITEM_DEF
}item_t;
static item_t s_item_init = {
#define ITEM_DEF(name, idx, val) .name = val,
ITEM_DEF_LIST
#undef ITEM_DEF
代碼中使用ITEM_DEF_LIST
統(tǒng)一定義了所有的子項(xiàng)名字和對應(yīng)的值,ITEM_DEF
在不同的場合定義不同的實(shí)現(xiàn),可以看到,ITEM_DEF
在枚舉item_n
中添加各個名字和對應(yīng)的序號,在結(jié)構(gòu)體item_t
中添加所有的名字。然后在全局靜態(tài)變量s_item_init
中添加初始化的值。測試如下:
#define ITEM_DEF(name, idx, val) \
printf("%s: enum: %d val: %d\n", \
STR(s_item_init.name), \
(int)NAME2(item, name), \
s_item_init.name);
/*
輸出:
s_item_init.a1: enum: 1 val: 1
s_item_init.a2: enum: 2 val: 3
s_item_init.a3: enum: 3 val: 5
s_item_init.a4: enum: 4 val: 7
s_item_init.a5: enum: 5 val: 9
*/
ITEM_DEF_LIST
#undef ITEM_DEF
2結(jié)語
C語言還有非常多的高級宏的寫法,有空再分享一波!