#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
роста код становится все хуже поддерживать, потому что
-
если команда не будет поддерживаться, люди могут удалить неправильную строку в массиве указателей функций.
-
если я хочу знать
cmd_Z
, что делать, я должен сосчитать от 1 до 26. -
список
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 /…