Один из наиболее частых способов применения директивы #define – создание макроопределений замаскированных под функции. Для макросов состоящих из одной инструкции, это легко. Просто определяем макрос без точки с запятой.
#define StartAdc() ADCSRA |= (1<<ADSC)
…
InitAdc(); //обычная функция
StartAdc(); //макрос
Но что делать, если макрос состоит из двух и более инструкций?
#define StartAdc() ADCSRA |= (1<<ADSC); \
asm(“sei”)
В общем случае, можно вызывать этот макрос как обычно.
StartAdc();
Препроцессор заменит макроопределение и точка с запятой окажется после второй строчки.
ADCSRA |= (1<<ADSC);
asm(“sei”);
Но что произойдет, если мы используем макрос там, где ожидается только одна инструкция?
if( … )
StartAdc();
Препроцессор заменит это на
if( … )
ADCSRA |= (1<<ADSC);
asm(“sei”);
Первая строчка макроопределения станет телом оператора if, а вторая в него не попадет, и будет выполняться всегда.
Можно ограничить определение макроса фигурными скобками {}
#define StartAdc() {ADCSRA |= (1<<ADSC); asm(“sei”);}
if( … )
StartAdc();
Препроцессор заменит это на
if( … )
{ADCSRA |= (1<<ADSC); asm(“sei”);};
На помощь приходит оператор do{…}while().
Определяем макрос следующим образом:
#define StartAdc() do{ADCSRA |= (1<<ADSC); asm(“sei”);}while(0)
И вуаля…
if(…)
StartAdc();
else
…
Препроцессор заменит этот макрос и точка с запятой окажется на вполне законном месте – после оператора while.
if(…)
do{ADCSRA |= (1<<ADSC); asm(“sei”);}while(0);
else
#define StartAdc() ADCSRA |= (1<<ADSC); \
asm(“sei”)
if( … ){
StartAdc();
}
Препроцессор заменит это на
if( … ){
ADCSRA |= (1<<ADSC);
asm(“sei”);
}


[code] [/code]