Как связать X-макрос с массивом указателя функции

#c #c-preprocessor #function-pointers #x-macros

#c #c-препроцессор #функции-указатели #x-макросы

Вопрос:

Я применил механизм X-macro для получения отношения перечисления к строке.

 #define CMD_TABLE 
                     X(cmd_A)
                     X(cmd_B)
////////////////////////////////////
typedef enum
{
    EMPTY, 
#define X(x) x,
    CMD_TABLE
#undef X
}cmd_t;
////////////////////////////////////
const static struct
{
    char* name;
    cmd_t index;
} conversionMap[] = {
#define X(x) {#x, x},
        CMD_TABLE
#undef X
};
  

Затем эта функция преобразует строку в enum .

 cmd_t str2enum(const char* str);
  

Наконец, соответствующая функция вызывается путем обработки enum как индекса массива.

 (*func[index])();
  

У этого метода есть большая проблема, заключающаяся в том, что он заставляет программиста запоминать отношение отображения перечисления к функции.

Другими словами, на этапе инициализации порядок следования следующих функций

 void (*func[])(void) = 
{
    amp;cmd_A_function,
    amp;cmd_B_function,
};
  

должно быть таким же, как у CMD_TABLE .

Кроме того, после CMD_TABLE роста код становится все хуже поддерживать, потому что

  1. если команда не будет поддерживаться, люди могут удалить неправильную строку в массиве указателей функций.

  2. если я хочу знать cmd_Z , что делать, я должен сосчитать от 1 до 26.

  3. список CMD_TABLE и void (*func[])(void) будет находиться далеко друг от друга, так что программисту необходимо написать код в двух местах, чтобы добавить одну функцию.

Комментарии:

1. Почему бы вам не использовать третий вариант X-макроса? Или, что еще лучше, используйте версию X-macros без определения.

2. Вы могли бы использовать свой CMD_TABLE снова, с макросом X, который превращается X(cmd_A) в amp;cmd_A_function, . Верно? Но вы знаете, как это сделать, не так ли?

3. EMPTY В начале перечисления нарушается согласованность между перечислениями и индексами массива. Не очень хорошая идея.

4. Избавьтесь от первого EMPTY перечисления, это только вызовет проблемы при таком подходе.

Ответ №1:

Вы уже дважды использовали X-macro.
Вы можете использовать его в третий раз.
Вот предложение, как это сделать, используя уродливый шаблон undef-using, который вы применяли первые два раза:

 void (*func[])(void) = 
{
#define X(x) amp;x##_function,
    CMD_TABLE
#undef X
};
  

Комментарии:

1. Такого рода макросы сложны. Если это не удается для вас, пожалуйста, предоставьте результат выполнения -E компилятора (т. Е. Предварительно обработанный код) и сравните его с тем, каким он должен быть. Затем я сделаю все возможное, чтобы это исправить.

2. Уродливый или нет, я считаю, что это самый распространенный способ написания X макросов.

3. @Lundin Да. Жаль.

4. Я придумал альтернативу: softwareengineering.stackexchange.com/questions/419695 /…