0

Simple idea:

I'm using X-macros to define command list structure and declare command callbacks.

#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;
}

it works.

helloworld
help!


Adding some parameters:

If you change the first command list to this (by adding parameters)

#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;

then, when running it I get the following error:

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

I have to use all the parameters for the command list definition (command declaration):

#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},

but it's quite tricky to now use it for the callback declaration...

Is there a clever way for this X-macro to avoid this error?


I thought about the non-macro way to mask unused parameters:

which is by using (void)param;, which gives the ugly

#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)

and this does not work...I get a strange:

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

I think there is another way:

maybe using something like this...

#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)) \

也许真相在别处...... :)

任何提示?

4

1 回答 1

1

这是整个 X 宏的一个问题——你必须编写一个接受所有参数的宏,即使你只使用了一些参数。

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

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

如果您只显式命名此特定宏感兴趣的参数,然后让其余参数进入...然后被忽略的部分。

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

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

你可以写一个只使用toto_all, or toto_alland的宏1,但是你不能写一个只使用1and的宏3。对于这种特殊情况,我相信您仍然必须命名所有宏参数。

另一种选择是自记录代码:

#define COMMAND_DEF(COMMAND_NAME, ignored1, FOO, ignored2, ignored3) \
/* do stuff with COMMAND NAME and FOO only */
于 2020-02-24T11:46:56.120 回答