Машина состояний на указателях на функции

Машина состояний

Для ускорения работы программы можно использовать указатели на функции (англ. function pointers): переход по указателю с вычислительной точки зрения почти ничего не стоит (сохранение переменных в стеке, запись адреса возврата), чего нельзя сказать про условные операторы (если их много и предугадать их не получается). Кроме того, это хороший способ продемонстрировать возможность обратного вызова функции (англ. callback). Модифицируем предыдущий пример, убрав switch / case конструкцию из главного цикла.

Для начала создадим тип указателя на функцию:

// state_machine.h
typedef void (STATE_FUNC_PTR_t)();

Затем нужно создать прототипы функций, в которых будет зашита логика поведения устройства. Сколько состояний — столько и функций. Также добавим глобальную переменную, отвечающую за состояние и хранящую адрес вызываемой функции.

// state_machine.h
void *state_time();
void *state_temperature();
void *state_adjust_hours();
void *state_adjust_minutes();
STATE_FUNC_PTR_t state = state_time;

Далее в исходном файле машины состояний пропишем логику программы. Как и в предыдущий раз, будем реагировать на изменение глобальной переменной event.

// state_machine.c
void *state_time() {
    // do some logic here
    display_time();
    return (event == EVENT_BUTTON_PRESSED) ? state_temperature : state_time; // next state
}
// … others

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

int main() {
    init_mcu();
    while(1) {
        state = (STATE_FUNC_PTR_t)(*state)();
    }
}

Изменено: