Какой лучший способ получить «пронумерованные» параметры конфигурации от препроцессора C? - PullRequest
0 голосов
/ 14 декабря 2009

У нас есть библиотека, которая обеспечивает доступ к кнопкам на устройстве. Эти кнопки перечисляются в остальной части системы как «кнопка питания» и так далее. Таким образом, остальным приложениям не нужно беспокоиться о том, как реализована «кнопка питания».

Мы собираем эту библиотеку, используя несколько директив конфигурации, которые выглядят так (упрощенно):

#define BUTTON_COUNT 2
#define BUTTON_0_NAME "power"
#define BUTTON_1_NAME "reset"
#define BUTTON_2_NAME NULL

Вопрос в том, что в какой-то момент я хочу получить имя кнопки 1. В идеале, я бы сделал это, создав функцию типа get_button_name(int index). Проблема в том, что я не могу найти хороший способ получить пронумерованные параметры конфигурации в этой функции. Текущая реализация выглядит так:

const char* get_button_name(int index) {
    switch (index) {
        case 0: return BUTTON_0_NAME;
        case 1: return BUTTON_1_NAME;
        case 2: return BUTTON_2_NAME;
    }
    return NULL;
}

Проблема в том, что этот код является общим для многих устройств, поэтому количество поддерживаемых кнопок будет продолжать увеличиваться. Это означает изменение этой функции, и все устройства, которые ее задействуют, должны добавить #define для новых кнопок.

Что бы я действительно предпочел (хотя я не думаю, что это возможно с препроцессором), это что-то вроде:

const char* get_button_name(int index) {
    if (index < BUTTON_COUNT) {
        return BUTTON_ ## index ## _NAME;
    }
    return NULL;
}

Есть идеи для лучшего решения?

Ответы [ 5 ]

5 голосов
/ 14 декабря 2009

Как насчет наличия массива?

 const char *buttons[] = {
   "power",
   "reset"};

 const char* get_button_name(int index) {
     if (index < sizeof(buttons)/sizeof(buttons[0])) {
         return buttons[index];
     }
     return NULL;
 }
1 голос
/ 14 декабря 2009

Вы не можете вернуть во время компиляции (preproc const) то, что вы запрашиваете во время выполнения (параметр в функции).

Вам нужно найти способ переместить все эти имена в какой-либо массив (lookup codegen, T4 и т. Д.) затем выполните простой поиск

1 голос
/ 14 декабря 2009

Я бы, наверное, написал код примерно так:

char const *names[] = {"power", "reset"};
#define elements(array) (sizeof(array)/sizeof(array[0]))

char const *get_button_name(size_t index) { 
    if (index < elements(names))
       return names[index];
    return NULL;
}
0 голосов
/ 15 декабря 2009

Я бы использовал массив. Если вы определяете массив как extern, вы можете объявить его во внешнем модуле отдельно от вашей функции get_button_name (). Например:

<code>
extern char const *names[] = {"power", "reset", "etc."};</p>

<p><code>#define num_names 3</code></p>

<p>char const *get_button_name(int index){
  if(index < num_names)
    return names[index];
  return NULL;
}

Я не думаю, что вы можете использовать sizeof (names [0]), особенно если ваши имена будут разных размеров.

0 голосов
/ 15 декабря 2009

Можете ли вы изменить свои директивы конфигурации? Или обработайте текст в следующей форме:

Buttons.h:

#define MAKEBUTTONS() const char* gButtonNames[\
"power",\
"reset",\
"macroize",\
]

extern const char* gButtonNames[];
#define GET_BUTTON_NAME(n) gButtonNames[n]

Тогда только один исходный файл должен содержать MAKEBUTTONS(); в глобальной области видимости, и любой клиентский код может вызвать GET_BUTTON_NAME() вместо функции.

...