微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

使用可变参数宏

如何解决使用可变参数宏

我有以下类型定义:

typedef struct {
  int (*function)(int argc,char *argv[]);
  char *name;
} command_t;

成员 function一个函数指针,成员 name一个字符串,用于存储函数名称

为了初始化 command_t 类型的变量,我编写了以下宏:

#define COMMAND(x) (command_t){.function = x,.name = #x}

这是我目前初始化 command_t 数组的方法

int ls(int argc,char *argv[]);
int echo(int argc,char *argv[]);
int cat(int argc,char *argv[]);
int mkdir(int argc,char *argv[]);

command_t cmd_list[] = {COMMAND(ls),COMMAND(echo),COMMAND(cat),COMMAND(mkdir)};

我希望能够初始化一个 command_t 数组:

command_t cmd_list[] = COMMAND(ls,echo,cat,mkdir);

command_t cmd_list[] = {COMMAND(ls,mkdir)};

我知道 COMMAND 必须是一个可变参数宏才能这样做,但我不知道如何编写它。

解决方法

//stringification of the argument Arg
#define PP_STRINGIFY(Arg) PP_STRINGIFY_(Arg)
#define PP_STRINGIFY_(Arg) #Arg

//concatenation of the two arguments
#define PP_CAT2(_1,_2) PP_CAT_(_1,_2)
#define PP_CAT_(_1,_2) _1##_2

//enumerate the number of arguments (min:1,max: 8)
#define PP_VA_NUM_ARGS(...) PP_VA_NUM_ARGS_(__VA_ARGS__,8,7,6,5,4,3,2,1)
#define PP_VA_NUM_ARGS_(_1,_2,_3,_4,_5,_6,_7,_8,N,...) N

//a single command initializer
#define COMMAND(x) (command_t){.function = x,.name = PP_STRINGIFY(x)}

//command list initializer
#define COMMAND_LST(...) { PP_CAT2(COMMAND_LST_,PP_VA_NUM_ARGS(__VA_ARGS__))(__VA_ARGS__) }

//implement as many as you need
//maybe you need to extend PP_VA_NUM_ARGS (current max limit 8)
#define COMMAND_LST_1(_1) COMMAND(_1)
#define COMMAND_LST_2(_1,_2) COMMAND(_1),COMMAND(_2)
#define COMMAND_LST_3(_1,_3) COMMAND_LST_2(_1,_2),COMMAND(_3)
#define COMMAND_LST_4(_1,_4) COMMAND_LST_3(_1,_3),COMMAND(_4)

typedef struct {
    int (*function)(int argc,char *argv[]);
    char *name;
} command_t;

int ls(int argc,char *argv[]);
int echo(int argc,char *argv[]);
int cat(int argc,char *argv[]);
int mkdir(int argc,char *argv[]);

int main()
{
    command_t cmd_lst[] = COMMAND_LST(ls,echo,cat,mkdir);
    return 0;
}

CPP 输出通过

gcc -E main.c

给你

command_t cmd_lst[] = { 
    (command_t){.function = ls,.name = "ls"},(command_t){.function = echo,.name = "echo"},(command_t){.function = cat,.name = "cat"},(command_t){.function = mkdir,.name = "mkdir"} 
};
,

我认为您已经接近最易读的形式了。尝试创建尽可能简单的代码。因此,与其发明一些奇怪的宏,以至于没有 C 程序员在不经过大量宏的情况下才能理解它的作用,您可以为整个初始化列表创建一个宏 - 这是相当普遍的做法。

即:command_t cmd_lst[] = COMMAND_INIT; 然后:

#define COMMAND(cmd) { .function = cmd,.name = #cmd }
#define COMMAND_INIT { COMMAND(ls),COMMAND(echo),COMMAND(cat),COMMAND(mkdir) }

另一个选项是 X 宏。它们不一定更具可读性,但可能会减少其他地方的代码重复:

#define FUNC_LIST(X) \
  X(ls)              \
  X(echo)            \
  X(cat)             \
  X(mkdir)           \

...

#define COMMAND_INIT(func) { .function = func,.name = #func },command_t cmd_lst[] = { FUNC_LIST(COMMAND_INIT) };

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?