C의 상태 머신

Waqar Aslam 2023년10월12일
  1. 상태 머신 개요
  2. 함수 포인터를 사용하여 상태 머신 생성
  3. Switch 문을 사용하여 상태 머신 생성
C의 상태 머신

이 기사에서는 C 프로그래밍 언어로 상태 시스템을 구현하는 방법을 보여줍니다.

상태 머신 개요

상태 시스템을 사용하여 코드를 구현하는 것은 복잡한 엔지니어링 문제를 해결하는 데 유용한 설계 전략입니다. 상태 기계는 전체 설계를 취하여 상태 기계 전문 용어 내에서 상태라고 하는 여러 단계로 나눕니다.

모든 국가는 특정 기능을 수행할 책임이 있습니다. 반면에 이벤트는 상태 머신이 상태 간에 변경되도록 하는 자극입니다. “전환"이라고도 합니다.

처음 작성되었을 때 대부분의 시스템은 간단하고 잘 구성되어 있지만 새로운 기능이 추가되면 이벤트 기록을 추적하기 위해 추가 플래그와 변수가 생성됩니다.

그런 다음 ifelse 문을 추가하여 많은 변수 및 플래그에서 생성된 훨씬 더 복잡한 논리 표현식을 테스트합니다.

이와 관련하여 상태 머신이 도움이 됩니다. 적절하게 활용하면 상태 기계는 각 분기점에서 테스트된 조건을 단순화하고 다양한 프로그램 실행 모드 간 전환을 더 쉽게 만듭니다.

대부분의 실시간 시스템의 동작은 상대적으로 적은 수의 겹치지 않는 청크(상태)로 나눌 수 있습니다.

각 청크 내의 이벤트 응답은 현재 이벤트에만 의존하며 더 이상 과거에 발생한 일련의 이벤트에 의존하지 않습니다.

함수 포인터를 사용하여 상태 머신 생성

다음은 C에서 상태 시스템을 구축하는 코드의 예입니다. 이 특정 예는 두 개의 상태 스위치를 앞뒤로 10번 생성합니다.

그런 다음 색인 번호와 해당 색인에 해당하는 상태를 표시합니다.

#include <stdio.h>

struct state;
typedef void state_fn(struct state *);

struct state {
  state_fn *next;
  int i;
};

state_fn off_state, on_state;

void off_state(struct state *state) {
  printf("%s %i\n", __func__, ++state->i);
  state->next = on_state;
}

void on_state(struct state *state) {
  printf("%s %i\n", __func__, ++state->i);
  state->next = state->i < 10 ? off_state : 0;
}

int main(void) {
  struct state state = {off_state, 0};
  while (state.next) state.next(&state);
}

출력:

off_state 1
on_state 2
off_state 3
on_state 4
off_state 5
on_state 6
off_state 7
on_state 8
off_state 9
on_state 10

Switch 문을 사용하여 상태 머신 생성

제대로 시작하려면 프로그램이 있을 수 있는 상태 집합과 프로그램이 처리할 수 있는 이벤트 집합을 나열해야 합니다.

이 프로그램은 START, ITERATE, 또는 END의 세 가지 상태 중 하나일 수 있습니다.

enum states {
  START,
  ITERATE,
  END,
} state;

START LOOPING, SHOW_MESSAGESTOP LOOPING 이벤트를 처리할 수 있습니다. START 상태에 있는 동안 START LOOPING 이벤트를 수신한 후 프로그램은 ITERATE 상태로 전환됩니다.

ITERATE 상태에 있는 동안 SHOW_MESSAGE 이벤트를 수신하면 메시지를 표시합니다. 마지막으로 STOP LOOPING 이벤트를 수신한 후 END 상태로 전환됩니다.

enum events {
  START_LOOPING,
  SHOW_MESSAGE,
  STOP_LOOPING,
};

현재 상태를 보고 적절한 사례를 실행하는 switch 문을 사용합시다. START ITERATEEND라고 하는 세 가지 기본 상황이 있습니다.

START 케이스 내에서 수신된 이벤트가 START LOOPING이면 상태가 ITERATE로 변경됩니다. 이벤트가 START LOOPING이 아니면 케이스가 깨집니다.

마찬가지로 ITERATE 사례에서 수신된 이벤트가 SHOW MESSAGE인 경우 메시지를 표시합니다. 그렇지 않으면 STOP LOOPING 사례를 확인하고 상태를 END로 변경합니다.

이러한 이벤트가 수신되지 않으면 중단되고 다음 케이스로 넘어갑니다. 마지막으로 END 케이스로 인해 switch 문이 종료되고 프로그램이 종료됩니다.

void switchState(enum events event) {
  switch (state) {
    case START:
      switch (event) {
        case START_LOOPING:
          state = ITERATE;
          break;
        default:
          exit(1);
          break;
      }
      break;
    case ITERATE:
      switch (event) {
        case SHOW_MESSAGE:
          printf("State Machine Ready!\n");
          break;
        case STOP_LOOPING:
          state = END;
          break;
        default:
          exit(1);
          break;
      }
      break;
    case END:
      exit(1);
      break;
  }
}

마지막으로 switchState()라는 메서드를 호출하고 이벤트를 인수 형식으로 한 번에 하나씩 제공합니다.

int main(void) {
  switchState(START_LOOPING);
  switchState(SHOW_MESSAGE);
  switchState(STOP_LOOPING);
  return 0;
}

다음은 switch 문을 사용하는 전체 소스 코드입니다.

#include <stdio.h>
#include <stdlib.h>

enum states {
  START,
  ITERATE,
  END,
} state;

enum events {
  START_LOOPING,
  SHOW_MESSAGE,
  STOP_LOOPING,
};

void switchState(enum events event) {
  switch (state) {
    case START:
      switch (event) {
        case START_LOOPING:
          state = ITERATE;
          break;
        default:
          exit(1);
          break;
      }
      break;
    case ITERATE:
      switch (event) {
        case SHOW_MESSAGE:
          printf("State Machine Ready!\n");
          break;
        case STOP_LOOPING:
          state = END;
          break;
        default:
          exit(1);
          break;
      }
      break;
    case END:
      exit(1);
      break;
  }
}

int main(void) {
  switchState(START_LOOPING);
  switchState(SHOW_MESSAGE);
  switchState(STOP_LOOPING);
  return 0;
}

출력:

State Machine Ready!
작가: Waqar Aslam
Waqar Aslam avatar Waqar Aslam avatar

I am Waqar having 5+ years of software engineering experience. I have been in the industry as a javascript web and mobile developer for 3 years working with multiple frameworks such as nodejs, react js, react native, Ionic, and angular js. After which I Switched to flutter mobile development. I have 2 years of experience building android and ios apps with flutter. For the backend, I have experience with rest APIs, Aws, and firebase. I have also written articles related to problem-solving and best practices in C, C++, Javascript, C#, and power shell.

LinkedIn