(我从Stefan Henneken 在 T_Arg 上的博客文章中收集了我的问题的解决方案。)
目标可以实现,但不是特别干净。有两种适用的通用类型(到目前为止我已经找到):ANY_NUM
和T_Arg
.
(我使用ANY_NUM
它是因为它与这个例子最相关。ANY
, ANY_REAL
, 或者ANY_INT
也是合理的选择)
这两个选项具有相似的结构和相似的功能。每个都是一个包含存储变量信息的结构:它的类型、指向它的指针和它的大小。
然而,各有利弊。为了最准确地解决这个问题,我们将使用T_Arg
.
这是区别:
ANY / ANY_NUM / ETC
优点:变量转换为在分配变量时隐式ANY_NUM
完成。输入变量在输入到函数之前不需要进行预转换,从而减少了代码的大小。
此外,它只接受属于其域的变量,因此不会意外使用字符串。
缺点: ANY_NUM
不能在VAR_INPUT
块之外声明,事实上,在尝试时会提供此错误消息:
Variables of type 'ANY_NUM' only allowed as input of functions.
因此ANY_NUM
不能用作STRUCT
变量,即使它STRUCT
被声明为函数的输入。这就是为什么它不能用来解决这个特定问题的原因。
T_Arg
优点: T_Arg
可以在任何地方声明和使用。
缺点: T_Arg
需要任何预期变量类型的转换函数,例如:
F_INT()
、、、F_REAL()
等F_DINT()
。
因此需要在输入前后进行类型检查。
示例解决方案
T_Arg
不幸的是,不能直接操作存储在其中的变量。必须将存储的变量移动到临时变量中才能使用它。所以Value
,Min_
和Max_
都需要从 type 转换T_Arg
为 type REAL
/ INT
/etc。
由于我们试图只使用 one STRUCT
,因此一旦完成操作,Value
就需要再次将其转换为 T_Arg 。Bind_Value
总共Value
将在实例化时转换三次,之后每次调用转换两次。
结构:
TYPE Bounded_Value:
STRUCT
Value : T_Arg;
Min_ : T_Arg;
Max_ : T_Arg;
END_STRUCT
END_TYPE
功能块:
FUNCTION_BLOCK Bind_Value
VAR_IN_OUT
value_struct: Bounded_Value;
// Other variable type declarations
END_VAR
VAR
val_int : INT;
max_int : INT;
min_int : INT;
END_VAR
CASE (value_struct.Value.eType) OF
E_ArgType.ARGTYPE_INT: // If the struct's Value's type is INT
// Copy generic pointer information into typed pointer
MEMCPY(ADR(val_int), value_struct.Value.pData, value_struct.Value.cbLen);
MEMCPY(ADR(max_int), value_struct.Max_.pData, value_struct.Max_.cbLen);
MEMCPY(ADR(min_int), value_struct.Min_.pData, value_struct.Min_.cbLen);
IF val_int > max_int THEN
value_struct.Value.pData := value_struct.Max_.pData;
ELSIF val_int < min_int THEN
value_struct.Value.pData := value_struct.Min_.pData;
END_IF
// Other variable type handlings
END_CASE
主要的:
PROGRAM MAIN
VAR
val : INT := -1; //Change this to test
minim : INT := 0;
maxim : INT := 5;
newVal : INT;
bv : Bounded_Value;
bind : Bind_Value;
END_VAR
// Convert INT variables to T_Arg in structure
bv.Value:= F_INT(val);
bv.Max_ := F_INT(maxim);
bv.Min_ := F_INT(minim);
// Bind_Value.value_struct := bv;
bind(value_struct := bv);
// Copy result to newVal
MEMCPY(ADR(newVal), bv.Value.pData, bv.Value.cbLen);