ITPub博客

首页 > 数据库 > 数据库开发技术 > 分享几个优雅的C/C++宏

分享几个优雅的C/C++宏

原创 数据库开发技术 作者:Rust嵌入式 时间:2024-01-09 21:58:13 0 删除 编辑

Part1优雅的C/C++ 宏

1引言

在C或C++开发中,我们经常会在代码中使用一些宏来简化编码,提升可阅读性。这里我总结了一些常用的、有趣的宏。

NAME2/UNIQUE_NAME

NAME2宏的实现如下,功能是将两个字符连接成一个字符。对于UNIQUE_NAME宏,则是在NAME2的基础上增加一个__LINE__参数,从而生成一个根据当前调用处的行数生成一个以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为计算静态数组的长度。IS_ARRAY则是判断参数的类型是否为数组,而非指针。定义如下:

#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为遍历数组的每个元素,第三个参数为闭包,可以被宏内部调用。

#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为定义一系列相同的清单项,如子项名与序号等,实现如下。

#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统一定义了所有的子项名字和对应的值,ITEM_DEF在不同的场合定义不同的实现,可以看到,ITEM_DEF在枚举item_n中添加各个名字和对应的序号,在结构体item_t中添加所有的名字。然后在全局静态变量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结语

C语言还有非常多的高级宏的写法,有空再分享一波!


原文作者:Rust嵌入式;如有侵权,请联系管理员删除。

请登录后发表评论 登录
全部评论

注册时间:2023-11-13

  • 博文量
    64
  • 访问量
    45582