如何在状态机上使用全局变量

How to use global variables on a state machine

我制作了这个状态机:

 enum states { STATE_ENTRY, STATE_....} current_state;
 enum events { EVENT_OK, EVENT_FAIL,EVENT_REPEAT, MAX_EVENTS } event;
 void (*const state_table [MAX_STATES][MAX_EVENTS]) (void) = {
   { action_entry , action_entry_fail , action_entry_repeat }, /* 
                                                  procedures for state 1 */
  ......}

void main (void){
   event = get_new_event (); /* get the next event to process */
   if (((event >= 0) && (event < MAX_EVENTS))
   && ((current_state >= 0) && (current_state < MAX_STATES))) {
      state_table [current_state][event] (); /* call the action procedure */
      printf("OK 0");
   } else {
      /* invalid event/state - handle appropriately */
         }
}

当我在一个状态下修改全局变量时,全局变量保持不变,而我在所有状态下都需要该变量。你现在可能是什么问题? 我的全局变量是这样的结构:

  #if (CPU_TYPE == CPU_TYPE_32)
     typedef uint32_t word;
     #define word_length 32
     typedef struct BigNumber {
     word words[64];
    } BigNumber;
   #elif (CPU_TYPE == CPU_TYPE_16)
    typedef uint16_t word;
    #define word_length 16
    typedef struct BigNumber {
    word words[128];
    } BigNumber;
   #else
     #error Unsupported CPU_TYPE
  #endif
  BigNumber number1 , number2;

 Here is how I modify:
 //iterator is a number from where I start to modify,
 //I already modified on the same way up to the iterator
 for(i=iterator+1;i<32;i++){
     nr_rand1=661;
     nr_rand2=1601;
     nr_rand3=1873;
     number2.words[i]=(nr_rand1<<21) | (nr_rand2<<11) | (nr_rand3);
  }

这只是为了防止您可能想要更改定义 FSM 的方法。我会给你举个例子;假设您有以下 FSM:

您可以将其表示为:

void function process() {
   fsm {
     fsmSTATE(S) {
       /* do your entry actions heare */
       event = getevent();
       /* do you actions here */
       if (event.char == 'a') fsmGOTO(A); 
       else fsmGOTO(E);
     }

     fsmSTATE(A) {
       event = getevent();
       if (event.char == 'b' || event.char == 'B') fsmGOTO(B); 
       else fsmGOTO(E);
     }

     fsmSTATE(B) {
       event = getevent();
       if (event.char == 'a' ) fsmGOTO(A); 
       else fsmGOTO(E);
     }
     fsmSTATE(E) {
       /* done with the FSM. Bye bye! */
     }
   }
}

我确实声称(但我相信有人会不同意)这比使用 table 更简单、更易读并且直接传达了 FSM 的结构。就算不放图,画FSM图也很简单

要得到这个,你只需按如下方式定义 fsmXXX 内容:

#define fsm            
#define fsmGOTO(x)    goto fsm_state_##x
#define fsmSTATE(x)   fsm_state_##x :

关于修改的代码number2:

for(i=iterator+1;i<32;i){
    nr_rand1=661;
    nr_rand2=1601;
    nr_rand3=1873;
    number2.words[i]=(nr_rand1<<21) | (nr_rand2<<11) | (nr_rand3);
}

我不能不注意到:

  • i 永远不会递增,因此在无限循环中只会更改数组的一个元素 (iterator+1);
  • 即使 i 会递增,也只有 words 数组的一部分会根据 iterator 的值进行更改(但这可能是预期的行为)。
  • 除非 iterator 可以是 -1,否则元素 words[0] 永远不会改变(同样这可能是预期的行为)。

我会检查这是否真的是您想要做的。

如果您确定这只是一个可见性问题(因为您说过当您将其声明为本地时它会按预期工作),我唯一能想到的另一件事是您将这些功能集于一身文件和主文件(或你检查的地方)在另一个文件中。

然后你在两个文件中包含相同的 .h 头,你最终(由于你使用的链接器)有两个不同的 number2 因为你没有将它声明为 extern 在两个文件之一中。 您的编译器(或者,更好的是,链接器)应该(至少)警告过您,您是否检查了编译消息?

这不是答案,而是评论。但它太大了,不适合评论区,所以我 post 暂时放在这里。

问题中 posted 的代码不足以找到根本原因。您需要 post 一个最小但完整的示例来说明问题。

类似于:

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

typedef uint32_t word;
#define word_length 32
typedef struct BigNumber {
  word words[4];
} BigNumber;

BigNumber number2;

enum states { STATE_0, STATE_1} current_state;
enum events { EVENT_A, EVENT_B } event;

void f1(void)
{
  int i;
  current_state = STATE_1;
  for (i=0; i<4; ++i) number2.words[i] = i;
}

void f2(void)
{
  int i;
  current_state = STATE_0;
  for (i=0; i<4; ++i) number2.words[i] = 42 + i*i;
}

void (*const state_table [2][2]) (void) =
{
    { f1 , f1 },
    { f2 , f2 }
};


int main (void){
  current_state = STATE_0;

  event = EVENT_A;
  state_table [current_state][event] (); /* call the action procedure */
  printf("%u %u %u %u\n", number2.words[0], number2.words[1], number2.words[2], number2.words[3]);

  event = EVENT_B;
  state_table [current_state][event] (); /* call the action procedure */
  printf("%u %u %u %u\n", number2.words[0], number2.words[1], number2.words[2], number2.words[3]);

  return 0;
}

以上可以算得上是最小的和完整的了。现在用你自己的一些函数更新这段代码,post 作为问题(如果它仍然失败)。

我的代码没有失败。

输出:

0 1 2 3
42 43 46 51