принудительно использовать неиспользуемый параметр для макроса - PullRequest
0 голосов
/ 24 февраля 2020

Простая идея:

Я использую X-макросы для определения структуры списка команд и объявления обратных вызовов команд.

#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-макроса избежать этой ошибки?


Я думал о немакро-способе маскировки неиспользуемых параметров:

, используя (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)) \

Может быть, истина в другом месте ...:)

есть намеки?

1 Ответ

1 голос
/ 24 февраля 2020

Это общая проблема макросов X - вы должны написать макрос, принимающий все параметры, даже если вы используете только несколько.

В вашем случае вы передаете макрос Speci c в качестве параметра в список, чтобы вы могли добавить некоторую гибкость. Использование макроса variadi c может решить проблему. Вы должны быть в состоянии сделать это следующим образом:

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

Если вы только явно указываете параметры, которые интересует этот конкретный макрос, то оставьте остальные из них go в части ..., которая затем игнорируется.

Однако это создает зависимость в данных, поскольку позволяет расширять параметры, так сказать, слева направо. Таким образом, для

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

вы можете написать макрос, который использует только toto_all, или toto_all и 1, но вы не сможете написать макрос, который просто использует, например, 1 и 3. Я полагаю, что для таких особых случаев вам все равно придется называть все параметры макроса.

Еще один вариант - самодокументируемый код:

#define COMMAND_DEF(COMMAND_NAME, ignored1, FOO, ignored2, ignored3) \
/* do stuff with COMMAND NAME and FOO only */
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...