У меня есть C программы с уменьшающимися счетчиками программного обеспечения. Например, если я хочу мигать светодиодом каждые 2 секунды, я могу сделать:
if(!ledT) {
ledT = 200;
// code
// code
// code
}
Поскольку я всегда делаю одну и ту же комбинацию с каждым счетчиком, я стараюсь набирать его одной строкой.
if(!ledT) { ledT = 200;
// code
// code
// code
}
Для всей строки if вместо этого я хотел бы использовать макрос. Таким образом, код будет выглядеть примерно так:
expired(ledT, 200) {
// code
// code
// code
}
Я использую что-то подобное в своем коде конечного автомата для состояния входа.
if(runOnce) { runOnce = false;
// code
// code
// code
Желаемый синтаксис:
entryState {
// code
// code
// code
.
#define entryState if(runOnce) { runOnce = false; // this ofcourse cannot work But something like this is what I want.
Я сделал несколько попыток, но ничего не получилось. Проблема в том, что '{' находится где-то посередине макроса, и я хочу напечатать '{' позади макроса, потому что, как мы все знаем, ни один редактор кода не может жить с неравным количеством '{' и '}'
expired(ledT, 200); // expired is macro, not function
// code
// code
// code
}
так что об этом не может быть и речи
Читая о макросах, я прочитал кое-что интересное об использовании: do ... пока (0). Этот «трюк» использует функцию оптимизации компилятора для создания определенного макроса, который в противном случае был бы невозможен.
Этот сайт
проливает некоторый свет на этот способ.
Есть ли способ использовать какой-то «макро-трюк» для достижения того, что я хотите?
и снова, это преобразует:
// this
if(runOnce) {
runOnce = false;
// code
// code
// code
// into this
entryState {
// code
// code
// code
// and this:
if(!someTimer) {
someTimer = someInterval;
// code
// code
// code
// must be transformed into:
timeExpired(someTimer, someInterval) {
// code
// code
// code
И ответ типа «Нет, это просто невозможно сделать» также будет принят (при условии, что вы знаете, о чем говорите )
РЕДАКТИРОВАТЬ: мне нужно добавить дополнение, потому что не все, кажется, знают, что я хочу, последний ответ даже не направлен на конкретную проблему c под рукой. Каким-то образом переключение IO вдруг стало важным? Поэтому я изменил свои примеры кода, чтобы лучше проиллюстрировать, в чем проблема.
EDIT2: я согласен, что макрос timeExpired вообще не улучшает читаемость
Чтобы показать, что некоторые макросы могут улучшить читабельность, я приведу фрагмент состояния и конечного автомата. Вот как сгенерированное состояние выглядит в моем коде:
State(stateName) {
entryState {
// one time only stuff
}
onState {
// continous stuff
exitFlag = true; // setting this, exits the state
}
exitState {
// one time only stuff upon exit
return true;
}
}
В настоящее время используется с этими макросами:
#define State(x) static bool x##F(void)
#define entryState if(runOnce)
#define onState runOnce = false;
#define exitState if(!exitFlag) return false; else
Я думаю, мне следует обменять return true;
в состояниях на EXIT
или что-то более приличное. И конечный автомат, который вызывает эти состояния, выглядит следующим образом:
#undef State
#define State(x) break; case x: if(x##F())
extern bit weatherStates(void) {
if(enabled) switch(state){
default: case weatherStatesIDLE: return true;
State(morning) {
if(random(0,1)) nextState(afternoon, 0);
else nextState(rain, 0); }
State(afternoon) {
nextState(evening, 0); }
State(evening) {
if(random(0,1)) nextState(night, 0);
else nextState(thunder, 0); }
State(night) {
nextState(morning, 0); }
State(rain) {
nextState(evening, 0); }
State(thunder) {
nextState(morning, 0); }
break; }
else if(!weatherStatesT) enabled = true;
return false; }
#undef State
Единственное, что не генерируется, это «if» и «else» перед функциями «nextState ()». Эти «условия потока» необходимо заполнить.
Если пользователю предоставляется небольшой пример или объяснение, у него не должно возникнуть никаких проблем с заполнением состояний. Он также должен иметь возможность добавлять состояния вручную.
Я бы даже хотел обменять это макросами:
extern bit weatherStates(void) {
if(enabled) switch(state){
default: case weatherStatesIDLE: return true;
и
break;} }
else if(!weatherStatesT) enabled = true;
return false;}
Зачем мне это делать? это? Чтобы скрыть неактуальную информацию из вашего дисплея. Чтобы убрать много вкладок в автомате. Для повышения общей читабельности с помощью простого синтаксиса. Как и в случае с третьими библиотечными функциями, вам нужно знать, как использовать код, а не знать, как эта функция работает.
Вам не нужно знать, как состояние сигнализирует о том, что оно готово. Более важно знать, что рассматриваемая функция используется как функция состояния, чем знать, что она возвращает битовую переменную.
Также я тестирую макросы перед использованием. Поэтому я не предоставляю кому-то конечные автоматы, которые могут показывать странное поведение.