为宏强制未使用的参数

force unused parameter for macro

简单的想法:

我正在使用 X-macros 来定义命令列表结构并声明命令回调。

#include <stdio.h>
#include <stddef.h>
#include <stdint.h>
#include <stdbool.h>
#include <string.h>

#define COMMAND_LIST(X) \
        X(toto_all) \
        X(help) \
        //end of list

typedef void (*callback_t)(int a, int b);

typedef struct 
{
    char * name;    
    callback_t callback;
}command_t;


#define CALLBACK_DEC(COMMAND_NAME)  void _##COMMAND_NAME(int a, int b);
COMMAND_LIST(CALLBACK_DEC)

#define COMMAND_DEF(COMMAND_NAME)  { #COMMAND_NAME, & _##COMMAND_NAME },
static command_t commands[] =
{
  COMMAND_LIST(COMMAND_DEF)
};

#define COMMAND(COMMAND_NAME,CODE)          void _##COMMAND_NAME(int A, int B) {  CODE  }

COMMAND(toto_all,
    printf("helloworld\n");
)

COMMAND(help,
    printf("help!\n");
)

int main()
{
    commands[0].callback(1,2);
    commands[1].callback(1,2);

    return 0;
}

有效。

helloworld
help!


添加一些参数:

如果将第一个命令列表改成这个(通过添加参数)

#define COMMAND_LIST(X) \
        X(toto_all,         1,      3,      5) \
        X(help,             0,      0,      0) \
        //end of list

typedef struct 
{
    callback_t callback;
    char * name;  
    int arg_min; 
    int arg_max;
    int arg_num;
}command_t;

然后,当 运行 它出现以下错误时:

macro "CALLBACK_DEC" passed 4 arguments, but takes just 1

我必须使用命令列表定义(命令声明)的所有参数:

#define COMMAND_DEF(COMMAND_NAME, ARG_MIN, ARG_MAX, ARG_MAX, ARG_NUM)  (command_t){ #COMMAND_NAME, & _##COMMAND_NAME, ARG_MIN, ARG_MAX, ARG_NUM},

但现在将其用于回调声明非常棘手...

这个X-macro有什么巧妙的方法可以避免这个错误吗?


我想到了屏蔽未使用参数的非宏方法:

这是通过使用(void)param;, 这给了丑陋的

#define CALLBACK_DEC(COMMAND_NAME, ARG_MIN, ARG_MAX, ARG_NUM) void _##COMMAND_NAME(int a, int b); void(ARG_MIN); void(ARG_MAX);  void(ARG_NUM)

这行不通...我觉得很奇怪:

main.c:27:20: error: expected identifier or ‘(’ before numeric constant
         X(toto_all,0,0,0) \

我觉得还有一个办法:

也许使用类似这样的东西...

#define COMMAND_LIST(X,Y) \
        X(Y(toto_all,         0,      0,      0)) \
        X(Y(help,             0,      0,      0)) \
        //command name,    arg min, arg max, arg num, string?
        //end of list

typedef void (*callback_t)(int a, int b);

typedef struct 
{
    char * name;    
    callback_t callback;
}command_t;

#define GET_ONLY_NAME(COMMAND_NAME1, ARG_MIN, ARG_MAX, ARG_NUM) COMMAND_NAME1
#define CALLBACK_DEC(COMMAND_NAME)  void _##COMMAND_NAME(int a, int b);
COMMAND_LIST(CALLBACK_DEC,GET_ONLY_NAME);
#undef CALLBACK_DEC

#define GET_FULL_LIST(X) X
#define COMMAND_DEF(COMMAND_NAME, ARG_MIN, ARG_MAX, ARG_NUM)  (command_t){ #COMMAND_NAME, & _##COMMAND_NAME, ARG_MIN, ARG_MAX, ARG_NUM},
static command_t commands[] =
{
  COMMAND_LIST(COMMAND_DEF,GET_FULL_LIST)
};
#undef COMMAND_DEF

但我仍然得到以下奇怪的错误,扩展中有问题但我看不到哪里...

main.c:27:31: error: expected ‘)’ before numeric constant
         X(Y(toto_all,         0,      0,      0)) \

也许真相在别处……:)

有什么提示吗?

这是 X 宏总体上的一个问题 - 您必须编写一个接受所有参数的宏,即使您只使用几个参数也是如此。

在您的情况下,您将特定的宏作为参数传递给列表,因此您可以在其中增加一些灵活性。使用可变参数宏可能会解决问题。你应该可以这样做:

#define COMMAND_DEF(COMMAND_NAME, ...)  { #COMMAND_NAME, & _##COMMAND_NAME },
...
COMMAND_LIST(COMMAND_DEF)

你只明确命名这个特定宏感兴趣的参数,然后让其余参数进入 ... 部分,然后被忽略。

然而,这确实在数据中建立了依赖关系,因为它只允许您从左到右扩展参数,可以这么说。所以对于

X(toto_all,         1,      3,      5,      "-")

您可以编写仅使用 toto_alltoto_all1 的宏,但您无法编写仅使用例如 [=16] 的宏=] 和 3。对于这种特殊情况,我相信您仍然必须命名所有宏参数。

另一种选择是自文档化代码:

#define COMMAND_DEF(COMMAND_NAME, ignored1, FOO, ignored2, ignored3) \
/* do stuff with COMMAND NAME and FOO only */