Могу ли я использовать препроцессор, чтобы сделать это более ясным?
Я писал небольшую функцию исходного файла для моего Pic32, и я застрял на одной вещи.
Это в основном утилита, которая должна хранить данные incomming char
в буфер, а затем, если 'r'
получен, он сравнивает буфер со списком команд (в массиве names
), и если соответствие найдено, возвращается индекс элемента.
Эта часть из заголовка:
#define NAMECNT 6
static const char names[NAMESCNT][10] = { // 6commands, max 10 char each
"korr", // 1
"adc", // 2
"fft", // 3
"data", // 4
"pr", // 5
"prsc"}; // 6
/* functions */
extern int comm(char cdata);
В главном файле есть один большой переключатель:
switch( comm(recieved_ch) ){
case 1: foo1(); break;
case 2: foo2(); break;
...
}
Теперь, для большей ясности, я хотел использовать вместо 1, 2,... оригинальные имена (например, case KORR: case ADC:
), поэтому я написал дефиниции для каждого из них
#define KORR 1
#define ADC 2
Но мне не нравится это решение, потому что я хочу использовать этот исходный файл в большем количестве проектов, и для каждого из них будет свой список команд. Есть ли способ, как это сделать?
Лучше всего было бы создать имена массивов в препроцессоре, но я сомневаюсь, что это вообще возможно. Я думал об использовании типа enum (который будет иметь те же элементы, что и список команд names
), но я не знаю, как это пройдет.2 ответа:
Вы можете использовать X-макросы для построения
enum
и заполнения массива, затем вы можете использовать значенияenum
вswitch
:#define VARS \ X(korr) \ X(adc) \ X(fft) \ X(data) \ X(pr) \ X(prsc) static const char names[][10] = { // 6commands, max 10 char each #define X(name) #name, VARS #undef X }; enum evars { #define X(name) name, VARS #undef X }; extern int comm(char cdata); int main(void) { char x = 1; switch (comm(x)) { case korr: printf("korr"); break; case adc: printf("adc"); break; /* ... and so on */ } return 0; }
Расширение
X
таково:static const char names[][10] = { "korr", "adc", "fft", "data", "pr", "prsc", }; enum evars { korr, adc, fft, data, pr, prsc, };
Edit: как указывает @5gon12eder, вам не нужно жестко кодировать 6 в первом измерении массива (вы можете оставить его неопределенным).
Я думаю, что препроцессор мог бы сделать здесь все более ясным, используя оператор конкатенации
##
, но это не даст преимущества в производительности. Операторswitch
может быть оптимизирован компилятором, но это зависит от реализации.Вместо "одного большого переключателя" используйте массив указателей функций. Что-то вроде
func_ptrs[comm(received_ch) - 1]();
Вызовет соответствующую функцию, где
В конце концов, вы убиваете двух зайцев одним выстрелом: вы создаете простой способ добавлять команды и улучшать производительность.foo1
находится в индексе0
,foo2
at1
и др. Чтобы добавить команду, просто добавьте имя команды в поле список команд и указатель на функциюfunc_ptrs
.
Кроме того, линейный поиск по массиву строк довольно неэффективен. Хэш-таблица даст преимущество в производительности.