如何在状态机上使用全局变量
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
我制作了这个状态机:
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