Трюк с #define

   Один из наиболее частых способов применения директивы #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”);};

   Точку с запятой после тела оператора if компилятор проглотит. Никакого криминала здесь нет. Однако этот вариант решения проблемы не будет работать в операторе if…else

   На помощь приходит оператор 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

   Красиво, да?
   Красиво, но зачем нам лишний код, возникнет у кого-то вопрос. Не волнуйтесь. Тело цикла выполнится всего лишь один раз и компилятор, будучи не дураком, не добавит в код ни одной лишней строчки.  
   Впервые я увидел этот трюк в битовых макросах. Помню долго не мог понять, нафига это сделано. Потом мне попался на глаза материал по препроцессору и тогда до меня дошло.
 

P.S.: Более очевидный способ решения подобной проблемы - всегда использовать парные скобки {} для ограничения тела операторов.

#define StartAdc()     ADCSRA |= (1<<ADSC); \
                               asm(“sei”)


if( … ){
    StartAdc();
}

Препроцессор заменит это на

if( … ){
   ADCSRA |= (1<<ADSC);
   asm(“sei”);
}

и код будет корректный.
Какой вариант использовать решать вам, но теперь вы не будете удивлены,  увидев подобную конструкцию в чужом коде.

У вас недостаточно прав для комментирования.