PLC結構化文字(ST)——指標和引用(Pointer&Reference)

J_Sheng發表於2024-09-04

PLC Structured Text Object Oriented Programming

PLC結構化文字(ST)——指標和引用(Pointer&Reference)

指標的定義

指標是一個變數,其值為另一個變數的地址,即,記憶體位置的直接地址。就像其他變數或常量一樣,您必須在使用指標儲存其他變數地址之前,對其進行宣告。---C++ 指標|菜鳥教程

解釋一下這裡為什麼不繼續引用C#Java的定義,因為C#Java明確刪除了指標,所以找不到關於指標的介紹。

引用的定義

引用變數是一個別名,也就是說,它是某個已存在變數的另一個名字。一旦把引用初始化為某個變數,就可以使用該引用名稱或變數名稱來指向變數。---C++ 引用|菜鳥教程

指標與引用的區別

引用很容易與指標混淆,它們之間有三個主要的不同:

  • 不存在空引用。引用必須連線到一塊合法的記憶體。
  • 一旦引用被初始化為一個物件,就不能被指向到另一個物件。指標可以在任何時候指向到另一個物件。
  • 引用必須在建立時被初始化。指標可以在任何時間被初始化。
    ---C++ 引用 vs 指標

指標的使用

在程式(PRG)中宣告整型(INT)變數'in01',再宣告指標變數指向INT型別。

PROGRAM Main
VAR
    in01    : INT;
    pint    : POINTER TO INT;
END_VAR

在程式碼編輯區使用取址運算子獲取變數“ in01 ”的記憶體地址賦值給指標變數“ pint ”,然後對指標變數解除地址引用賦值44,最終變數in01當前值為44。

pint := ADR(in01);
if pint<>0 then
    pint^ := 44; 
END_IF

引用的使用

PROGRAM Main
VAR
    in01    : INT;
    refint    : REFERENCE TO INT;
END_VAR
------------
refint REF= in01;
if __ISVALIDREF(refint) then
    refint := 11;
END_IF

在程式碼編輯區引用型別變數refint使用REF=運算子與整型變數in01建立引用關係,然後將refint賦值11,最終變數in01當前值為11。

Tips : 某些情況下會存在空引用,所以在使用REFERENCE引用型別時,一般做有效引用的判斷運算子 __ISVALIDREF,若引用物件不為空則返回TRUE,若為無效引用則返回FALSE。

指標實現Fluent

  • 建立 FB_StringBuilder 功能塊
FUNCTION_BLOCK FB_StringBuilder
VAR
	sContent : STRING;
END_VAR
  • 實現 Append 方法,返回指標型別指向 FB_StringBuilder
METHOD Append : POINTER TO FB_StringBuilder
VAR_INPUT
	sText : STRING;
END_VAR
-------------------
sContent := CONCAT(STR1 := sContent, STR2 := sText);
Append := THIS; // THIS指標指向自身例項物件
  • 實現 Clear 方法,返回指標型別指向 FB_StringBuilder
METHOD Clear : POINTER TO FB_StringBuilder
VAR_INPUT
END_VAR
------------------
sContent := '';
Clear := THIS; // THIS指標指向自身例項物件
  • 實現 ToString 方法,返回STRING型別
METHOD ToString : STRING
VAR_INPUT
END_VAR
------------------
ToString := sContent;
  • Main函式宣告及呼叫
PROGRAM MAIN
VAR
	// 輸出'Hello world'
	fbStringBuilder : FB_StringBuilder;
	sResult : STRING;
	bTest : BOOL;
END_VAR
------------------
IF bTest THEN
	sResult := fbStringBuilder.Clear()^
								.Append('H')^
								.Append('e')^
								.Append('l')^
								.Append('l')^
								.Append('o')^
								.Append(' ')^
								.Append('W')^
								.Append('o')^
								.Append('r')^
								.Append('l')^
								.Append('d')^
								.ToString();
	bTest := FALSE;
END_IF

使用指標也能實現“ Fluent ”效果,只是看起來一點都不優雅。

引用實現Fluent

  • 建立 FB_StringBuilder 功能塊
FUNCTION_BLOCK FB_StringBuilder
VAR
	sContent : STRING;
END_VAR
  • 實現 Append 方法,返回引用型別 FB_StringBuilder
METHOD Append : REFERENCE TO FB_StringBuilder
VAR_INPUT
	sText : STRING;
END_VAR
-------------------
sContent := CONCAT(STR1 := sContent, STR2 := sText);
Append REF= THIS^;
  • 實現 Clear 方法,返回引用型別 FB_StringBuilder
METHOD Clear : REFERENCE TO FB_StringBuilder
VAR_INPUT
END_VAR
------------------
sContent := '';
Clear REF= THIS^;
  • 實現 ToString 方法,返回STRING型別
METHOD ToString : STRING
VAR_INPUT
END_VAR
------------------
ToString := sContent;
  • Main函式宣告及呼叫
PROGRAM MAIN
VAR
	// 輸出'Hello world'
	fbStringBuilder : FB_StringBuilder;
	sResult : STRING;
	bTest : BOOL;
END_VAR
------------------
IF bTest THEN
	sResult := fbStringBuilder.Clear()
								.Append('H')
								.Append('e')
								.Append('l')
								.Append('l')
								.Append('o')
								.Append(' ')
								.Append('W')
								.Append('o')
								.Append('r')
								.Append('l')
								.Append('d')
								.ToString();
	bTest := FALSE;
END_IF

使用REFERENCE型別實現“ Fluent ”效果。綜合比較實現流式程式設計使用引用(REFERENCE)或者介面(INTERFACE) 效果會更好,編碼便捷。

總結

指標就是地址,引用是對指標的包裝,指標容易出現空指標,引用相對更安全,但仍需要注意出現空引用的情況。
這是目前IEC61131-3標準中我能想到的實現“Fluent”三種程式設計方式。若還有其它我不知道的方法,歡迎大神留言討論。

相關文章