2009-02-28 3 views
1

Я пишу прошивку в C для встроенного процессора. Я хочу иметь всю конфигурационную информацию в одном файле заголовка config.h. Это вызывает проблемы с инициализацией ADC, где простые #defines не будут делать трюк. Сейчас код примерно так:с использованием макросов для конфигурации

config.h

#define NUMBER_OF_POTS 1 
#define POT_1_CHANNEL 27 

adc.c

#define MAKE_CSS(channel) _CSS##channel 
#define CALL_MAKE_CSS(channel) MAKE_CSS(channel) 

void initialize_adc() { 
    CALL_MAKE_CSS(POT_1_CHANNEL); 
} 

То, что я хочу сделать, это не должны касаться adc.c, если я изменю конф. ч к:

#define NUMBER_OF_POTS 2 
#define POT_1_CHANNEL 27 
#define POT_2_CHANNEL 29 

adc.c должна просто автоматически добавить второй CALL_MAKE_CSS с некоторым макро обманом.

У меня вопрос: есть ли уловка, которая дает вам возможность цикла с макросом?

Thanks,

Steve.

ответ

3

Я не проверял это:

// config.h 

#define NUMBER_OF_POTS 2 
extern int pots[]; 

// config.c 

int pots[NUMBER_OF_POTS] = { 
    27, 
    29 
}; 


// adc.c 

void initialize_adc() { 
    for (int i = 0; i < NUMBER_OF_POTS; i++) { 
     CALL_MAKE_CSS(pots[i]); 
    } 
} 
+0

Я бы сделал массив pots [] статическим в adc.c. Зачем создавать глобальную переменную и новый файл config.c? –

+0

Вы также можете определить «int pots [] = {..}» и сделать NUMBER_OF_POTS расчет времени компиляции: #define NUMBER_OF_POTS (sizeof pots/sizeof (pots [1])) –

+0

Возможно, новый файл не требуется; имеет ли смысл сделать массив глобальным, зависит от того, где еще он может быть использован, и у нас недостаточно кода, чтобы это знать. Однако вполне правдоподобно думать, что могут быть и другие места, где он будет использоваться; одинаково, все они могут быть в adc.c. –

1

Вам не нужно полностью полагаться на макросы. Просто определите свои «магические числа» как #defines.

Например:

В config.h:

#define NUMBER_OF_POTS 2 
#define POT_1_CHANNEL 27 
#define POT_2_CHANNEL 29 

unsigned int PotChannelList[NUMBER_OF_POTS] = {POT_1_CHANNEL, POT_2_CHANNEL}; 

В adc.c:

for(i = 0; i < NUMBER_OF_CHANNELS; i++) 
{ 
    initialize_adc(PotChannelList[i]); 
} 

Вы все еще определяют установку в config.h и не должны измените adc.c при добавлении канала. Вы просто добавляете его в список. Порядок списка также определяет порядок инициализации.

EDIT: Извините за беспорядок форматирования ...

+0

Я второе содержание ответа, но это может понадобиться немного переформатировать ... – gimpf

+0

Там есть небольшая проблема с этим решением: любой файл, в том числе config.h будет иметь переменную PotChannelList. Если к нему добавлено более 1 единицы компиляции, будет ошибка связывания, потому что имя определено более одного раза. Решение состоит в том, чтобы сделать его статическим, но затем оно дублируется повсюду. –

+0

не быть педантичным, #defines - это макросы: p – hhafez

0

Посмотрите boost.preprocessor. Хотя boost обычно используется для C++, препроцессор метапрограммирует lib работает, ну, только с CPP, поэтому он может делать то, что вы хотите. Он предоставляет несколько структур данных (списки, кортежи) и макросы итераций.

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

Примечание Только что услышал ответ Шредера. Не полагаясь на ПП, если он не нужен еще лучший вариант ...

+0

У меня был хороший длинный взгляд на boost.preprocessor один раз на время (я подумывал об использовании его специально для получения цикла макросов). Я не рекомендую использовать его. Трюки, используемые для получения «петель» в макросах, слишком странны, чтобы оставить в коде код, с которым кто-то еще должен будет работать когда-нибудь. –

0

Препроцессор Си не может делать петли. Вам нужно либо выполнить цикл в C-коде, либо если вам нужно сделать что-то вроде цикла во время компиляции, вы можете написать собственный препроцессор (который может быть просто простым сценарием оболочки, например), который генерирует необходимый код.

0

Хотя вы не можете делать петли с препроцессором, вы можете сделать разворачивается петли.Поэтому, если вы знаете, что у вас никогда не будет более 4 горшков, вы можете это сделать;

void initialize_adc() { 
    #if NUMBER_OF_POTS > 0 
    CALL_MAKE_CSS(POT_1_CHANNEL); 
    #endif 
    #if NUMBER_OF_POTS > 1 
    CALL_MAKE_CSS(POT_2_CHANNEL); 
    #endif 
    #if NUMBER_OF_POTS > 2 
    CALL_MAKE_CSS(POT_3_CHANNEL); 
    #endif 
    #if NUMBER_OF_POTS > 3 
    CALL_MAKE_CSS(POT_4_CHANNEL); 
    #endif 
} 

Единственное преимущество этого в сравнении с другими решениями здесь заключается в том, что накладные расходы во время выполнения вообще отсутствуют. Дополнительный встроенный код «magically» появляется тогда и только тогда, когда добавляется другой канал, точно так же, как задавал вопрос. Чтобы извлечь уродство из функции вызова функции (за счет размещения ранее в коде вместо этого), определите 4 новых макроса, каждый из которых использует ту же технику #if NUMBER_OF_POTS> x. Тогда вы сможете просто пойти;

void initialize_adc() { 
    INIT_CSS_1(); 
    INIT_CSS_2(); 
    INIT_CSS_3(); 
    INIT_CSS_4(); 
} 
Смежные вопросы