Мне просто интересно узнать, есть ли у кого-нибудь хорошие учебные пособия в Интернете для разработки государственных машин. Или книги?
Я начинаю работать на государственных машинах и просто нуждаюсь в чем-то общем, чтобы начать меня.
Мне просто интересно узнать, есть ли у кого-нибудь хорошие учебные пособия в Интернете для разработки государственных машин. Или книги?
Я начинаю работать на государственных машинах и просто нуждаюсь в чем-то общем, чтобы начать меня.
Конечные автоматы очень просты в C, если вы используете указатели функций.
В основном вам нужно 2 массива - один для указателей функций состояния и один для правил перехода состояний. Каждая функция состояния возвращает код, вы просматриваете таблицу перехода состояний по состоянию и код возврата, чтобы найти следующее состояние, а затем просто выполнить его.
int entry_state(void);
int foo_state(void);
int bar_state(void);
int exit_state(void);
/* array and enum below must be in sync! */
int (* state[])(void) = { entry_state, foo_state, bar_state, exit_state};
enum state_codes { entry, foo, bar, end};
enum ret_codes { ok, fail, repeat};
struct transition {
enum state_codes src_state;
enum ret_codes ret_code;
enum state_codes dst_state;
};
/* transitions from end state aren't needed */
struct transition state_transitions[] = {
{entry, ok, foo},
{entry, fail, end},
{foo, ok, bar},
{foo, fail, end},
{foo, repeat, foo},
{bar, ok, end},
{bar, fail, end},
{bar, repeat, foo}};
#define EXIT_STATE end
#define ENTRY_STATE entry
int main(int argc, char *argv[]) {
enum state_codes cur_state = ENTRY_STATE;
enum ret_codes rc;
int (* state_fun)(void);
for (;;) {
state_fun = state[cur_state];
rc = state_fun();
if (EXIT_STATE == cur_state)
break;
cur_state = lookup_transitions(cur_state, rc);
}
return EXIT_SUCCESS;
}
Я не включаю функцию lookup_transitions()
, поскольку она тривиальна.
Вот так я делаю государственные машины годами.
Я предпочитаю использовать указатели функций над гигантскими операторами switch
, но в отличие от qrdl answer Я обычно не использую явные коды возврата или таблицы перехода.
Кроме того, в большинстве случаев вам понадобится механизм для передачи дополнительных данных. Вот пример конечного автомата:
#include <stdio.h>
struct state;
typedef void state_fn(struct state *);
struct state
{
state_fn * next;
int i; // data
};
state_fn foo, bar;
void foo(struct state * state)
{
printf("%s %i\n", __func__, ++state->i);
state->next = bar;
}
void bar(struct state * state)
{
printf("%s %i\n", __func__, ++state->i);
state->next = state->i < 10 ? foo : 0;
}
int main(void)
{
struct state state = { foo, 0 };
while(state.next) state.next(&state);
}
Государственные машины не являются чем-то, что по своей сути требует объяснения или даже использования учебника. Я предлагаю, чтобы вы взглянули на данные и как их нужно разбирать.
Например, мне пришлось проанализировать протокол данных для Near Space balloon flight computer, он хранил данные на SD-карте в определенной формат (двоичный), который необходимо разделить на разделенный запятыми файл. Использование конечного автомата для этого имеет наибольший смысл, потому что в зависимости от того, какой следующий бит информации нам нужно изменить, мы анализируем.
Код написан с использованием С++ и доступен как ParseFCU. Как вы можете видеть, он сначала определяет, какую версию мы анализируем, и оттуда он входит в две разные машины состояний.
Он входит в конечный автомат в известном хорошем состоянии, в этот момент мы начинаем синтаксический анализ и в зависимости от того, с какими символами мы сталкиваемся, мы либо переходим к следующему состоянию, либо возвращаемся к предыдущему состоянию. Это в основном позволяет коду самостоятельно адаптироваться к способу хранения данных и независимо от того, существуют или нет определенные данные вообще.
В моем примере строка GPS не является обязательной для регистрации бортового компьютера, поэтому обработка строки GPS может быть пропущена, если найдены конечные байты для этой единственной записи в журнале.
Государственные машины просты в написании, и в целом я следую правилу, которое оно должно протекать. Вход через систему должен протекать с определенной легкостью из состояния в состояние.
К сожалению, большинство статей о машинах состояний написаны для C++ или других языков, которые имеют прямую поддержку полиморфизма, так как было бы неплохо моделировать состояния в реализации FSM как классы, производные от абстрактного класса состояний.
Тем не менее, довольно легко реализовать конечные автоматы в C, используя операторы switch для отправки событий в состояния (для простых FSM они в значительной степени кодируются прямо) или используя таблицы для отображения событий в переходы состояний.
Здесь есть пара простых, но приличных статей о базовой структуре для конечных автоматов в C:
Отредактируйте: сайт "на обслуживании", ссылки на веб-архив:
Конечные автоматы на основе операторов switch
часто используют набор макросов, чтобы "скрыть" механику оператора switch
(или используют набор операторов if
/then
/else
вместо switch
) и сделать то, что составляет "язык FSM" для описания конечного автомата в C-источнике. Лично я предпочитаю табличный подход, но он, безусловно, имеет свои достоинства, широко используется и может быть эффективен, особенно для более простых автоматических автоматов.
Одна из таких основ описана Стивом Рабином в главе "Игровые программные жемчужины" 3.0 (Разработка общего надежного движка ИИ).
Подобный набор макросов обсуждается здесь:
Если вам также интересны реализации конечного автомата C++, то здесь можно найти гораздо больше. Я отправлю указатели, если вам интересно.
Объектно-ориентированное моделирование в реальном времени было фантастическим (опубликовано в 1994 году и теперь продается всего за 81 цент, плюс 3,99 доллара за доставку).
Это все, что вам нужно знать.
int state = 0;
while (state < 3)
{
switch (state)
{
case 0:
// Do State 0 Stuff
if (should_go_to_next_state)
{
state++;
}
break;
case 1:
// Do State 1 Stuff
if (should_go_back)
{
state--;
}
else if (should_go_to_next_state)
{
state++;
}
break;
case 2:
// Do State 2 Stuff
if (should_go_back_two)
{
state -= 2;
}
else if (should_go_to_next_state)
{
state++;
}
break;
default:
break;
}
}
Существует много уроков, чтобы узнать, как обрабатывать государственные машины в C, но позвольте мне также предложить компилятор конечного автомата Ragel:
http://www.complang.org/ragel/
Он имеет довольно простой способ определения состояний машин, а затем вы можете генерировать графики, генерировать код в разных стилях (управляемый таблицей, goto-driven), анализировать этот код, если хотите, и т.д. И он мощный, может быть используемый в производственном коде для различных протоколов.
Государственные машины могут быть очень сложными для сложной задачи. Они также подвержены неожиданным ошибкам. Они могут превратиться в кошмар, если кто-то сталкивается с ошибкой или нуждается в изменении логики в будущем. Их также трудно отслеживать и отлаживать без диаграммы состояния. Структурированное программирование намного лучше (например, вы, вероятно, не будете использовать конечный автомат на уровне магистрали). Вы можете использовать структурированное программирование даже в контексте прерывания (в котором обычно используются государственные машины). См. Эту статью "Макросы для имитации многозадачного/блокирующего кода на уровне прерываний" , найденного на codeproject.com.