Баловство с препроцессором -- немного оффтопик на Оберон-форуме, но позволяет продемонстрировать, как за счёт простейших сишных макросов можно не только симитировать
цикл Дейкстры, но и повысить надёжность софта за счёт автоматизации построения некоторых специализированных структур управления.
Вот, предположим, нужно, что бы в некоей процедуры куски кода выполнялись поочерёдно при каждом вызове этой процедуры, причём эти куски кода нежелательно выделять в отдельные процедуры, поскольку сами по себе они большого смысла не имеют.
В сях это можно изобразить примерно так:
void test(void)
{
static int step = 0;
switch (step++)
{
case 0:
printf("step 0\\n");
break;
case 1:
printf("step 1\\n");
break;
case 2:
printf("step 2\\n");
break;
case 3:
printf("step 3\\n");
default:
step = 0;
break;
}
}
void main(void)
{
int i;
for (i = 0; i < 10; i++)
{
test();
}
}
step 0
step 1
step 2
step 3
step 0
step 1
step 2
step 3
step 0
step 1
Проблема: нужно вручную помечать номер каждого шага в "case x:" (а их может быть немало, легко обсчитаться).
Решение проблемы: сделать макросы, иммтирующие новую языковую конструкцию, которые возьмут на себя эту рутину.
valeksey предложил
такой вариант:
#define FIRST(code) { int flag = 0; static int i = 0; if (i==0) { { code }; flag = 1; }
#define NEXT(code) if (!flag && i == __LINE__) { { code }; flag = 1; } else if (flag == 1) { i = __LINE__; flag=2;}
#define LAST(code) if (!flag && i == __LINE__) { { code }; i = 0; } else if (flag == 1) { i = __LINE__; } }
void test(void)
{
FIRST
(
printf("step 0\\n");
)
NEXT
(
printf("step 1\\n");
)
NEXT
(
printf("step 2\\n");
)
LAST
(
printf("step 3\\n");
)
}
Это решение меня смутило количеством if-ов и не вполне очевидной логикой работы, поэтому я сделал такой вариант:
#define FIRST(var) { static int STEPPER_##var##step = 0; switch (STEPPER_##var##step) { case 0:
#define NEXT(var) STEPPER_##var##step = __LINE__; break; case __LINE__:
#define END(var) default: STEPPER_##var##step = 0; break; } }
void test(void)
{
FIRST(some_id)
printf("step 0\\n");
NEXT(some_id)
printf("step 1\\n");
NEXT(some_id)
printf("step 2\\n");
NEXT(some_id)
printf("step 3\\n");
END(some_id)
}
Мне кажется, что тут логика выполнения более понятно, более нагляден поток выполнения в раскрытых макросах.
Ну и такой варант может быть вложенным, так как эта конструкция параметризуется неким идентификатором...