狀態機的三種騷操作,值得你了解

2021-12-24 小麥大叔

點擊上方「小麥大叔」,選擇「置頂/星標公眾號」

大家好,我是小麥,這次我們一起來學習C語言實現狀態機的三種方法解析。

狀態機的實現無非就是 3 個要素:狀態、事件、響應。轉換成具體的行為就 3 句話。

用 C 語言實現狀態機主要有 3 種方法:switch—case 法表格驅動法函數指針法

switch—case 法

狀態用 switch—case 組織起來, 將事件也用switch—case 組織起來, 然後讓其中一個 switch—case 整體插入到另一個 switch—case 的每一個 case 項中  。

「程序清單 List4  :」

switch(StateVal)
{
    case S0:
  switch(EvntID)
  {
   case E1:
    action_S0_E1(); /*S0 狀態下 E1 事件的響應*/
    StateVal = new state value;/*狀態遷移,不遷移則沒有此行*/
    break;
   case E2:
    action_S0_E2(); /*S0 狀態下 E2 事件的響應*/
    StateVal = new state value;
    break;
   .
   case Em:
    action_S0_Em(); /*S0 狀態下 Em 事件的響應*/
    StateVal = new state value;
    break;
   default:
    break;
  }
  break;
    case S1:
  .
  break;
    .
    case Sn:
  .
  break;
    default:
  break;
}

上面的偽代碼示例只是通用的情況,實際應用遠沒有這麼複雜。雖然一個系統中事件可能有很多種,但在實際應用中,許多事件可能對某個狀態是沒有意義的。

例如在程序清單 List4中,如果 E2、······ Em 對處在 S0 狀態下的系統沒有意義,那麼在 S0 的 case 下有關事件E2、······ Em 的代碼根本沒有必要寫,狀態 S0 只需要考慮事件 E1 的處理就行了。

既然是兩個 switch—case 之間的嵌套, 那麼就有一個誰嵌套誰的問題, 所以說 switch—case法有兩種寫法:狀態嵌套事件事件嵌套狀態。這兩種寫法都可以, 各有利弊, 至於到底選用哪種方式就留給設計人員根據具體情況自行決斷吧。

關於 switch—case 法還有最後一點要說明, 因為 switch—case 的原理是從上到下挨個比較,越靠後,查找耗費的時間就越長,所以要注意狀態和事件在各自的 switch 語句中的安排順序,不推薦程序清單 List4 那樣按順序號排布的方式。出現頻率高或者實時性要求高的狀態和事件的位置應該儘量靠前

表格驅動法

如果說** switch—case 法是線性的**,那麼表格驅動法則是平面的。表格驅動法的實質就是將狀態和事件之間的關係固化到一張二維表格裡, 把事件當做縱軸,把狀態當做橫軸,交點[Sn , Em]則是系統在 Sn 狀態下對事件 Em 的響應  。

如圖 4, 我把表格中的 Node_SnEm 叫做狀態機節點, 狀態機節點 Node_SnEm 是系統在 Sn狀態下對事件 Em 的響應。這裡所說的響應包含兩個方面:輸出動作和狀態遷移。狀態機節點一般是一個類似程序清單 List5 中的結構體變量 。

struct fsm_node
{
    void (*fpAction)(void* pEvnt);
    INT8U u8NxtStat;
};

程序清單 List5 中的這個結構體有兩個成員:fpAction 和 u8NxtStat。fpAction 是一個函數指針, 指向一個形式為 void func(void * pEvnt)的函數, func 這個函數是對狀態轉移中動作序列的標準化封裝。

也就是說, 狀態機在狀態遷移的時候, 不管輸出多少個動作、操作多少個變量、調用多少個函數,這些行為統統放到函數 func 中去做。

把動作封裝好了之後,再把封裝函數 func 的地址交給函數指針 fpAction,這樣,想要輸出動作,只需要調用函數指針 fpAction 就行了。

再看看上面的 func 函數,會發現函數有一個形參 pEvnt,這是一個類型為 void * 的指針, 在程序實際運行時指向一個能存儲事件的變量,通過這個指針我們就能獲知關於事件的全部信息,這個形參是很有必要的。

事件一般包括兩個屬性:事件的類型和事件的內容。

例如一次按鍵事件,我們不僅要知道這是一個按鍵事件,還要知道按下的到底是哪個鍵。

事件的類型和狀態機當前的狀態可以讓我們在圖 4 的表格中迅速定位,確定該調用哪個動作封裝函數, 但是動作封裝函數要正確響應事件還需要知道事件的內容是什麼, 這也就是形參pEvnt 的意義。

由於事件的多樣性,存儲事件內容的數據格式不一定一樣,所以就把 pEvnt 定義成了 void * 型,以增加靈活性。

有關 fpAction 的最後一個問題:如果事件 Em 對狀態 Sn 沒有意義,那麼狀態機節點Node_SnEm 中的 fpAction 該怎麼辦?

我的答案是:那就讓它指向一個空函數唄!前面不是說過麼,什麼也不幹也叫響應。

u8NxtStat 存儲的是狀態機的一個狀態值。我們知道, 狀態機響應事件要輸出動作, 也就是調用函數指針 fpAction 所指向的那個封裝函數, 函數調用完畢後程序返回主調函數, 狀態機對事件的響應就算結束了, 下一步就要考慮狀態遷移的問題了。

可能要保持本狀態不變, 也可能要遷移到一個新的狀態,該如何抉擇呢?u8NxtStat 存儲的狀態就是狀態機想要的答案!

圖 4 的這張表格反映在 C 語言代碼裡就是一個二維數組,第 1 維就是狀態機的狀態,第 2維就是統一分類的事件,而數組的元素則是程序清單 List5 中的結構體常量。

如果程序中使用表格驅動法,還需要注意一些特別的事項。要將狀態當做表格的橫軸,那麼就要求狀態值集合必須滿足以下條件

「事件」 作為縱軸,其特點和要求與用來做橫軸的「狀態」 完全一致。在 C 語言提供的數據類型中, 沒有比枚舉更符合以上要求的可選項了, 極力推薦將狀態集合和事件類型集合做成枚舉常量。表格驅動法的優點:調用接口統一 ,定位快速。

表格驅動法屏蔽了不同狀態下處理各個事件的差異性,因此可以將處理過程中的共性部分提煉出來,做成標準統一的框架式代碼,形成統一的調用接口。

根據程序清單 List5 中的狀態機節點結構體,做成的框架代碼如程序清單 List6 所示。

表格驅動法查找目標實際上就是一次二維數組的尋址操作,所以它的平均效率要遠高於switch—case 法。

「程序清單 List6  :」

extern struct fsm_node g_arFsmDrvTbl[][]; /*狀態機驅動表格*/
INT8U u8CurStat = 0; /*狀態暫存*/
INT8U u8EvntTyp = 0; /*事件類型暫存*/
void* pEvnt = NULL; /*事件變量地址暫存*/
struct fsm_node stNodeTmp = {NULL, 0}; /*狀態機節點暫存*/
u8CurStat = get_cur_state(); /*讀取當前狀態*/
u8EvntTyp = get_cur_evnt_typ(); /*讀取當前觸發事件類型*/
pEvnt = (void*)get_cur_evnt_ptr(); /*讀取事件變量地址*/
stNodeTmp = g_arFsmDrvTbl[u8CurStat ][u8EvntTyp ];/*定位狀態機節點*/
stNodeTmp.fpAction(pEvnt ); /*動作響應*/
set_cur_state(stNodeTmp.u8NxtStat); /*狀態遷移*/

表格驅動法好則好矣,但用它寫出來的程序還有點兒小問題,我們先來看看按照表格驅動法寫出來的程序有什麼特點 。

前面說過,表格驅動法可以把狀態機調度的部分做成標準統一的框架代碼,這個框架適用性極強, 不管用狀態機來實現什麼樣的應用, 框架代碼都不需要做改動, 我們只需要根據實際應用場合規劃好狀態轉換圖,然後將圖中的各個要素(狀態、事件、動作、遷移,有關「條件」要素一會兒再說)用代碼實現就行了,我把這部分代碼稱作應用代碼。

在應用代碼的.c 文件中, 你會看到一個聲明為 const 的二維數組, 也就是圖 4 所示的狀態驅動表格, 還會看到許多彼此之間毫無關聯的函數, 也就是前面提到的動作封裝函數。

這樣的一份代碼, 如果手頭上沒有一張狀態轉換圖, 讓誰看了也會一頭霧水, 這樣的格式直接帶來了代碼可讀性差的問題。

如果我們想給狀態機再添加一個狀態,反映到代碼上就是給驅動表格再加一列內容,同時也要新添加若干個動作封裝函數。

如果驅動表格很大, 做這些工作是很費事兒的, 而且容易出錯。如果不小心在數組中填錯了位置, 那麼程序跑起來就和設計者的意圖南轅北轍了,

遠沒有在 switch—case 法中改動來得方便、安全。Extended State Machine 的最大特點就是狀態機響應事件之前先判斷條件,根據判定結果選擇執行哪些動作,轉向哪個狀態。

也就是說,系統在狀態 Sn 下發生了事件 Em 後,轉向的狀態不一定是唯一的,這種靈活性是 Extended State Machine 的最有價值的優點。

回過頭來看看程序清單 List5 中給出的狀態機節點結構體,如果系統在狀態 Sn 下發生了事件 Em, 狀態機執行完 fpAction 所給出的動作響應之後, 必須轉到 u8NxtStat 指定的狀態。

表格驅動法的這個特性直接杜絕了 Extended State Machine 在表格驅動法中應用的可能性, 所以表格驅動法的代碼實現中不存在「條件」 這個狀態機要素。ESM,你是如此的優秀,我怎麼捨得拋棄你 ?!

再看圖 4 所示的表格驅動法示例圖,如果我們把表格中的代表事件的縱軸去掉,只留下代表狀態的橫軸,將一列合併成一格,前文提到的問題是不是能得到解決呢?不錯!這就是失傳江湖多年的《葵花寶典》 ——閹割版表格驅動法 !!

閹割版表格驅動法,又名壓縮表格驅動法,一維狀態表格與事件 switch—case 的合體。壓縮表格驅動法使用了一維數組作為驅動表格,數組的下標即是狀態機的各個狀態。

表格中的元素叫做壓縮狀態機節點, 節點的主要內容還是一個指向動作封裝函數的函數指針, 只不過這個動作封裝函數不是為某個特定事件準備的, 而是對所有的事件都有效的。

節點中不再強制指定狀態機輸出動作完畢後所轉向的狀態, 而是讓動作封裝函數返回一個狀態, 並把這個狀態作為狀態機新的狀態。

壓縮表格驅動法的這個特點, 完美的解決了 Extended State Machine 不能在表格驅動法中使用的問題

程序清單 List7 中的示例代碼包含了壓縮狀態機節點結構體和狀態機調用的框架代碼。

「程序清單 List7:」

struct fsm_node /*壓縮狀態機節點結構體*/
{
 INT8U (*fpAction)(void* pEvnt); /*事件處理函數指針*/
 INT8U u8StatChk; /*狀態校驗*/
};
.
u8CurStat = get_cur_state(); /*讀取當前狀態*/
.
if(stNodeTmp.u8StatChk == u8CurStat )
{
 u8CurStat = stNodeTmp.fpAction(pEvnt ); /*事件處理*/
 set_cur_state(u8CurStat ); /*狀態遷移*/
}
else
{
 state_crash(u8CurStat ); /*非法狀態處理*/
}

對照程序清單 List5,就會發現程序清單 List7 中 struct fsm_node 結構體的改動之處。首先, fpAction 所指向函數的函數形式變了,動作封裝函數 func 的模樣成了這樣的了:

INT8U func(void * pEvnt);

現在的動作封裝函數 func 是要返回類型為 INT8U 的返回值的,這個返回值就是狀態機要轉向的狀態, 也就是說, 壓縮表格驅動法中的狀態機節點不負責狀態機新狀態的確定, 而把這項任務交給了動作封裝函數 func, func 返回哪個狀態, 狀態機就轉向哪個狀態。

新狀態由原來的常量變成了現在的變量,自然要靈活許多。上面說到現在的動作封裝函數 func 要對當前發生的所有的事件都要負責, 那麼 func 怎麼會知道到底是哪個事件觸發了它呢?看一下 func 的形參 void * pEvnt 。

在程序清單 List5 中我們提到過,這個形參是用來向動作封裝函數傳遞事件內容的,但是從前文的敘述中我們知道, pEvnt 所指向的內存包含了事件的所有信息, 包括事件類型和事件內容 , 所以通過形參 pEvnt , 動作封裝函數 func 照樣可以知道事件的類型。

程序清單 List7 中 struct fsm_node 結構體還有一個成員 u8StatChk , 這裡面存儲的是狀態機 的一個狀態,幹什麼用的呢?

玩 C 語言數組的人都知道,要嚴防數組尋址越界。

要知道,壓縮表格驅動法的驅動表格是一個以狀態值為下標的一維數組, 數組元素裡面最重要的部分就是一個個動作封裝函數的地址。

函數地址在單片機看來無非就是一段二進位數據, 和內存中其它的二進位數據沒什麼兩樣,不管程序往單片機 PC 寄存器裡塞什麼值,單片機都沒意見。假設程序由於某種意外而改動了存儲狀態機當前狀態的變量,使變量值變成了一個非法狀態。

再發生事件時, 程序就會用這個非法的狀態值在驅動表格中尋址, 這時候就會發生內存洩露,程序拿洩露內存中的未知數據當函數地址跳轉,不跑飛才怪!

為了防止這種現象的發生, 壓縮狀態機節點結構體中又添加了成員 u8StatChk 。u8StatChk中存儲的是壓縮狀態機節點在一維驅動表格的位置, 例如某節點是表格中的第 7 個元素, 那麼這個節點的成員 u8StatChk 值就是 6。

看一下程序清單 List7 中的框架代碼示例, 程序在引用函數指針 fpAction 之前, 先檢查當前狀態和當前節點成員 u8CurStat 的值是否一致,一致則認為狀態合法,事件正常響應,如果不一致,則認為當前狀態非法,轉至意外處理,最大限度保證程序運行的安全。

當然,如果洩露內存中的數據恰好和 u8CurStat 一致,那麼這種方法真的就回天乏力了。

還有一個方法也可以防止狀態機跑飛,如果狀態變量是枚舉,那麼框架代碼就可以獲知狀態值的最大值, 在調用動作封裝函數之前判斷一下當前狀態值是否在合法的範圍之內, 同樣能保證狀態機的安全運行。

壓縮表格驅動法中動作封裝函數的定義形式我們已經知道了,函數裡面到底是什麼樣子的呢?程序清單 List8 是一個標準的示例。

「程序清單List8:」


INT8U action_S0(void* pEvnt)
{
 INT8U u8NxtStat = 0;
 INT8U u8EvntTyp = get_evnt_typ(pEvnt);
 switch(u8EvntTyp )
 {
  case E1:
   action_S0_E1(); /*事件 E1 的動作響應*/
   u8NxtStat = new state value; /*狀態遷移,不遷移也必須有本行*/
   break;
   .
  case Em:
   action_S0_Em(); /*事件 Em 的動作響應*/
   u8NxtStat = new state value; /*狀態遷移,不遷移也必須有本行*/
   break;
  default:
   ; /*不相關事件處理*/
   break;
 }
 return u8NxtStat ; /*返回新狀態*/
}

從程序清單 List8 可以看出, 動作封裝函數其實就是事件 switch—case 的具體實現。函數根據形參 pEvnt 獲知事件類型, 並根據事件類型選擇動作響應, 確定狀態機遷移狀態, 最後將新的狀態作為執行結果返回給框架代碼。

有了這樣的動作封裝函數, Extended State Machine 的應用就可以完全不受限制了!到此,有關壓縮表格驅動法的介紹就結束了。

個人認為壓縮表格驅動法是相當優秀的,它既有表格驅動法的簡潔、高效、標準,又有 switch—case 法的直白、靈活、多變,相互取長補短,相得益彰。

函數指針法

上面說過,用 C 語言實現狀態機主要有 3 種方法(switch—case 法、表格驅動法、函數指針法), 其中函數指針法是最難理解的, 它的實質就是把動作封裝函數的函數地址作為狀態來看待。不過,有了之前壓縮表格驅動法的鋪墊,函數指針法就變得好理解了,因為兩者本質上是相同的。

壓縮表格驅動法的實質就是一個整數值(狀態機的一個狀態)到一個函數地址(動作封裝函數)的一對一映射, 壓縮表格驅動法的驅動表格就是全部映射關係的直接載體。在驅動表格中通過狀態值就能找到函數地址,通過函數地址同樣能反向找到狀態值。

我們用一個全局的整型變量來記錄狀態值,然後再查驅動表格找函數地址,那乾脆直接用一個全局的函數指針來記錄狀態得了,還費那勞什子勁幹嗎?!這就是函數指針法的前世今生。

用函數指針法寫出來的動作封裝函數和程序清單 List8 的示例函數是很相近的, 只不過函數的返回值不再是整型的狀態值, 而是下一個動作封裝函數的函數地址, 函數返回後, 框架代碼再把這個函數地址存儲到全局函數指針變量中。

相比壓縮表格驅動法,在函數指針法中狀態機的安全運行是個大問題,我們很難找出一種機制來檢查全局函數指針變量中的函數地址是不是合法值。如果放任不管, 一旦函數指針變量中的數據被篡改,程序跑飛幾乎就不可避免了。

總結

有關狀態機的東西說了那麼多,相信大家都已經感受到了這種工具的優越性,狀態機真的是太好用了!其實我們至始至終講的都是有限狀態機(Finite State Machine 現在知道為什麼前面的代碼中老是有 fsm 這個縮寫了吧!), 還有一種比有限狀態機更 NB 更複雜的狀態機, 那就是層次狀態機(Hierarchical State Machine 一般簡寫為 HSM)。

通俗的說,系統中只存在一個狀態機的叫做有限狀態機,同時存在多個狀態機的叫做層次狀態機(其實這樣解釋層次狀態機有些不嚴謹, 並行狀態機也有多個狀態機, 但層次狀態機各個狀態機之間是上下級關係,而並行狀態機各個狀態機之間是平級關係)。

層次狀態機是一種父狀態機包含子狀態機的多狀態機結構,裡面包含了許多與面向對象相似的思想, 所以它的功能也要比有限狀態機更加強大, 當一個問題用有限狀態機解決起來有些吃力的時候, 就需要層次狀態機出馬了。

層次狀態機理論我理解得也不透徹, 就不在這裡班門弄斧了,大家可以找一些有關狀態機理論的專業書籍來讀一讀。要掌握狀態機編程,理解狀態機(主要指有限狀態機)只是第一步,也是最簡單的一步,更重要的技能是能用狀態機這個工具去分析解剖實際問題:劃分狀態、 提取事件、 確定轉換關係、規定動作等等,形成一張完整的狀態轉換圖,最後還要對轉換圖進行優化,達到最佳。

把實際問題變成了狀態轉換圖, 工作的一大半就算完成了, 這個是具有架構師氣質的任務,剩下的問題就是按照狀態圖編程寫代碼了,這個是具有代碼工特色的工作。

本文來源網絡,版權歸原作者所有。如涉及作品版權問題,請聯繫我進行刪除。


相關焦點

  • 簡單了解狀態機
    :moore、Mealy3、狀態機的主要用途4、C 語言實現簡單的狀態機1、有限狀態機(1)常說的狀態機是指有限狀態機 FSM(Finite State Machine)。(3)狀態機的3個關鍵點:當前狀態、外部輸入、下一個狀態。2、兩種狀態機Moore 型狀態機相對簡單,輸出只與當前的狀態有關(與輸入信號狀態無關)此時輸入信號也不是完全沒用,他的作用是用作 激勵作用。
  • 淺談狀態機
    而在建模仿真的領域中,狀態機又是逃不開的一個話題。狀態機(State Machine)是有限狀態自動機的簡稱,是現實事物運行規則抽象而成的一個數學模型。簡單來說,狀態機主要是用來描述事物或者事物間的狀態以及轉換的,舉個例子,現實的事物燈泡,一般來說只有兩個狀態:亮起和熄滅,燈泡的亮起和熄滅取決於開關這個事件,所以這個燈泡抽象成狀態機應該是如下圖所示:這就引出了狀態機中幾個比較重要的概念:狀態、事件、動作、轉換。
  • 渣男的騷操作了解一下
    渣男的騷操作了解一下時間:2020-06-08 18:38   來源:小雞詞典   責任編輯:沫朵 川北在線核心提示:原標題:跳軌什麼意思什麼梗?渣男的騷操作了解一下 是指微博上某網友分享的一種渣男的騷操作,即渣男每次和三兒睡之前,都先和女朋友分手,睡完再和好,使的在和人任何一個人睡時都保持單身, 簡直是道德楷模 (如下圖) 後網友又總結出《出軌詞典》如下: 跟原配掰   原標題:跳軌什麼意思什麼梗?
  • 運用狀態機提高嵌入式軟體效率
    如果合理運用狀態機機制開發系統軟體,就可以讓MCU進行多任務的分時處理。本文引用地址:http://www.eepw.com.cn/article/152440.htm1 建立有限狀態機的模型 其實在平時的程序設計中,開發人員已經不知不覺地使用了狀態機,如按鍵狀態轉換、菜單顯示狀態的轉換等。但是,很少有系統會使用狀態機進行多任務處理。
  • JavaScript狀態模式及狀態機模型
    開放-封閉原則(OCP)告訴我們要對擴展開放,對修改關閉,你可以繼承擴展我所有的能力,到你手裡你想咋改咋改,但是,別 動我 本人 好嗎?這使得你可以根據對象自身的情況將對象的狀態(動作——up,down,backward,forward)作為一個對象(Actions.up,Actions.down這樣),這一對象可以不依賴於其他對象而獨立變化(一個行為一個動作,互不幹擾)。
  • 面試經典問題系列--狀態機
    常見的I2C,APB協議中也有狀態機的影子,可以說是完完全全逃不掉,今天筆者就以自己的理解好好理一下狀態機的知識點。狀態機的提出會大大簡化這一工作。根據狀態機的輸出是否與輸入條件相關分為兩類:Moore狀態機、Mealy狀態機。Moore 狀態機:組合邏輯的輸出只取決於當前狀態。Mealy 狀態機:組合邏輯的輸出不僅取決於當前狀態,還取決於輸入狀態。
  • 狀態機設計原則:清晰!清晰!還是清晰!
    設計出超級狀態並不是什麼值得驕傲的本事,它單純:增加了旁人(以及幾個月後的自己)閱讀和理解狀態邏輯的難度回頭再看前面的例子,很容易發現,它違反了狀態功能單一原則:將字符輸出和判斷字符串尾部的功能集成進了同一個狀態,從而產生了一個擁有3條躍遷的超級狀態。基於狀態功能單一原則,一個更好的設計如下:
  • 單片機之狀態機淺談
    說到單片機編程,不得不說到狀態機,狀態機做為軟體編程的主要架構已經在各種語言中應用,當然包括C語言,在一個思路清晰而且高效的程序中,必然有狀態機的身影浮現。靈活的應用狀態機不僅是程序更高效,而且可讀性和擴展性也很好。
  • 認識一下Qt狀態機QStateMachine
    關於Qt狀態機的介紹就懶得說了,網絡上一搜一大堆,反正也看不懂。我關心的就是怎麼使用,畢竟我只是一個編寫應用程式的程式設計師。簡單粗暴地理解一下狀態機就是一個管理很多狀態的機器。組成一個最簡單的狀態機應該包括狀態機(QStateMachine)、狀態(QState)和過渡(QAbstractTransition子類)。狀態機就相當於一個容器,過渡就是將某一個狀態切換到另一個狀態(當然也可以不切換)。
  • C語言狀態機編程思想
    有限狀態機是一種概念思想,把複雜的控制邏輯分解成有限個穩定狀態,組成閉環系統,通過事件觸發,讓狀態機按設定的順序處理事務。
  • 獨家秘訣:用YAKINDU StatechartTools進行Java開發的圖形狀態機
    來源:Pexels你有沒有過看著自己的代碼,意識到它實際上是一個正嘗試使用的狀態機?通常你會開始使用switch-case語句或採用狀態模式。這種方法對於較大的狀態機來說難以快速讀取和維護。YAKINDU Statechart Tools附帶了一個圖形編輯器,可以為狀態圖建模並自動生成相應的Java代碼。人們還可以在圖形模型中直接使用Java代碼。
  • 多芬「騷操作」引人吐槽,但是它家的這3款好物,你可別錯過!
    前幾天多芬登上了熱搜,不是因為有什麼好物或者有什麼雷品,是因為一個迷惑性的「騷操作」引人吐槽。是什麼「騷操作」應該很多人都知道了吧?就是它竟然提前公布了超火爆女團選秀節目的C位,讓人覺得挺迷惑挺無語的。
  • Unity動畫系統詳解10:子狀態機是什麼?
    編輯子狀態機雙擊這個子狀態機可以打開它,界面會顯示這個子狀態機內的內容(初始會是一個空的狀態機)。子狀態機的Transition子狀態機只是從視覺上將一些狀態摺疊到一個子狀態機中,所以如果想轉換到sub-state machine時,需要選擇具體轉換到哪一個狀態或整個狀態機。
  • 火箭大勝湖人哈登騷操作!塗指甲油打比賽,還是粉色的!
    火箭大勝湖人哈登騷操作!除了出現了一個運球碰鬍子的失誤之外,還被球迷發現了另外一個騷操作,那就是塗指甲油打比賽,還是粉色的!可能觀看了直播的球迷,應該沒人發現哈登塗了粉絲指甲油吧?這也是小編賽後從一些比賽圖片中發現,很多比賽圖片並沒有直接拍到哈登指甲的情況,但是在無意當中,小編還是發現了一張哈登指甲的照片,指甲確實呈現出粉色指甲油的效果。
  • 函數指針方法實現簡單狀態機(附代碼)
    之前寫過一篇狀態機的實用文章,很多朋友說有幾個地方有點難度不易理解,今天給大家換種簡單寫法,使用函數指針的方法實現狀態機。狀態機簡介有限狀態機FSM是有限個狀態及在這些狀態之間的轉移和動作等行為的數學模型,是一種邏輯單元內部的高效編程方法,可以根據不同狀態或者消息類型進行相應的處理邏輯,使得程序邏輯清晰易懂。
  • 大學生怎樣避免掛科,感覺要掛科怎麼辦,這些騷操作,建議你收藏
    不掛科的大學是不完整的大學,大學生反駁:騙人,你給我掛個試試,以及掛科後的後果,和防止掛科的一些正規操作,正規操作靠自己的努力不掛科,確實值得喝彩,但有時後往往還是會有同學不想熬夜複習,或者時間已經來不及複習了,那這裡老學長就來告訴你一些防止掛科的騷操作。
  • 騷操作教你找回消失的群聊
    其實微信群並不是消失了,一般情況下分為三種情況1. 你不小心把微信群的聊天框刪除了或者換手機,刪微信從裝了,這是微信群找不到最高發的原因,也是微信群功能的特點,如果不特殊設置的話,你把聊天框刪除那麼這個群就不太好找到,一般情況下都是等人在這個群裡說話,那麼這個群會自動出現。2. 群解散或者你被踢出群聊了。
  • Android狀態機StateMachine
    工作中有一同事說到Android狀態機StateMachine。作為一名Android資深工程師,我居然沒有聽說過StateMachine,因此抓緊時間學習一下。StateMachine不是Android SDK中的相關API,其存在於frameworks層源碼中的一個Java類。可能因為如此,許多應用層的開發人員並未使用過。
  • 利用74LS161實現複雜狀態機
    打開APP 利用74LS161實現複雜狀態機 發表於 2018-01-18 09:00:02 狀態機的寫法