C FSM 状态的一种热编码

One hot encoding of the states of a C FSM

基本上,我只想知道手动对 C FSM 的状态进行热编码是否是个好主意。 我实现了它来编写一个简单的状态转换验证器:

typedef enum
{
    FSM_State1 = (1 << 0),
    FSM_State2 = (1 << 1),
    FSM_State3 = (1 << 2),
    FSM_StateError = (1 << 3)
} states_t;

然后验证:

states_t nextState, requestedState;
uint32_t validDestStates = 0;

// Compute requested state
requestedState = FSM_State1;

// Define valid transitions
validDestStates |= FSM_State2;
validDestStates |= FSM_State3;

// Check transition
if (validDestStates & requestedState)
{
    // Valid transition
    nextState = requestedState;
}
else
{
    // Illegal transition
    nextState = FSM_StateError;
}

我知道我只能使用最大整数。但是我没有那么多状态。所以这不是问题

还有比这个编码更好的吗? 是否有一些我还没有看到的缺点?

感谢您的帮助!

编辑:根据 user3386109 评论更改了验证测试


最后的想法

所以最后这是我所做的:

1/ 状态枚举是“经典”枚举:

typedef enum
{
    FSM_State1,
    FSM_State2,
    FSM_State3,
    FSM_StateError
} states_t;

2/ 有效转换的位字段:

struct s_fsm_stateValidation
{
    bool State1IsValid: 1;
    bool State2Valid: 1;
    bool State3IsValid: 1;
    bool StateErrorIsValid: 1;

    /// Reserved space for 32bit reserved in the union
    uint32_t reserved: 28;
};

3/ 为验证创建联合

typedef union FSM_stateValidation_u
{
    /// The bit field of critical system errors
    struct s_fsm_stateValidation state;
    /// Access the bit field as a whole
    uint32_t all;
} u_FSM_stateValidation;

4/ 我更改了验证:

u_FSM_stateValidation validDestStates;

// Set valid states
validDestStates.state.State1 = true;

// Compute requestedState
requestedState = FSM_State2;

if ((validDestStates.all & ((uint32_t) (1 << requestedState)) ))
{
    // Next state is legal
    return requestedState;
}
else
{
    return FSM_StateError;
}

从快速 Google 来看,"one hot encoded" 意味着每个有效代码都恰好设置了一位,这似乎就是您正在做的。搜索结果表明这是一种硬件设计模式。

我能想到的缺点是...

  1. 正如您所建议的,您极大地限制了有效代码的数量 - 对于 32 位,您最多有 32 codes/states 而不是超过 40 亿。

  2. 它不是查找表的理想选择,查找表是 switch 语句的常见实现。通常有一个内部函数可用于确定哪个是最低位集,但我不会打赌编译器会自动使用它。

不过,如果州的数量很少,这些都不是大问题。

那么 IMO 的问题是,是否有优势证明该成本是合理的。不一定要有很大的优势,但一定要有一点点。

我能想到的最好办法是您可以使用按位技巧来指定状态集,这样您就可以有效地测试当前状态是否在给定的集合中 - 如果您有一些需要完成的操作例如,在状态 (1<<0)(1<<3) 中,您可以测试 if (state & 0x9).