(я почерпнул решение своей проблемы из сообщения Стефана Хеннекена на 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_
потребуется преобразование из типа T_Arg
в тип REAL
/ INT
/ и т. Д.
Поскольку мы пытаемся использовать только один 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);