ГОСТ Р МЭК 61131-3-2016. Национальный стандарт Российской Федерации. Контроллеры программируемые. Часть 3. Языки программирования
6.4 Типы данных
6.4.1 Общие положения
Тип данных - это классификация, которая определяет возможные значения для литералов и переменных, операции, которые можно выполнять и способ хранения значений.
6.4.2 Элементарные типы данных (BOOL, INT, REAL, STRING и т.д.)
6.4.2.1 Спецификация элементарных типов данных
Настоящий стандарт устанавливает набор (предопределенных) элементарных типов данных.
Элементарные типы данных, ключевое слова для каждого типа данных, число битов на элемент данных и диапазон значений для каждого элементарного типа данных приведены в таблице 10.
Таблица 10
Элементарные типы данных
Номер | Описание | Ключевое слово | Неявное начальное значение | Длина (бит) <a> |
1 | Логический | BOOL | 0, FALSE | 1 <h> |
2 | Короткое целое | SINT | 0 | 8 <c> |
3 | Целое | INT | 0 | 16 <c> |
4 | Двойное целое | DINT | 0 | 32 <c> |
5 | Длинное целое | LINT | 0 | 64 <c> |
6 | Короткое целое без знака | USINT | 0 | 8 <d> |
7 | Целое без знака | UINT | 0 | 16 <d> |
8 | Двойное целое без знака | UDINT | 0 | 32 <d> |
9 | Двойное целое без знака | ULINT | 0 | 64 <d> |
10 | Действительные числа | REAL | 0.0 | 32 <e> |
11 | Длинные целые | LREAL | 0.0 | 64 <f> |
12a | Продолжительность времени | TIME | T#0s | -- <b> |
12b | Продолжительность времени | LTIME | LTIME#0s | 64 <m>, <q> |
13a | Дата (отдельно) | DATE | Примечание | -- <b> |
13b | Длинная дата (отдельно) | LDATE | LDATE#1970-01-01 | 64 <n> |
14a | Время суток (отдельно) | TIME_OF_DAY или TOD | TOD#00:00:00 | -- <b> |
14b | Время суток (отдельно) | LTIME_OF_DAY или LTOD | LTOD#00:00:00 | 64 <o>, <q> |
15a | Дата и время суток | DATE_AND_TIME или DT | Примечание | -- <b> |
15b | Дата и время суток | LDATE_AND_TIME или LDT | LDT#1970-01-01-00:00:00 | 64 <p>, <q> |
14a | Время суток (отдельно) | TIME_OF_DAY или TOD | TOD#00:00:00 | -- <b> |
14b | Время суток (отдельно) | LTIME_OF_DAY или LTOD | LTOD#00:00:00 | 64 <o>, q> |
15a | Дата и время суток | DATE_AND_TIME или DT | Примечание | -- <b> |
15b | Дата и время суток | LDATE_AND_TIME или LDT | LDT#1970-01-01-00:00:00 | 64 <p>, <q> |
16a | Строка однобайтовых символов переменной длины | STRING | " (пустая) | 8 <i>, <g>, <k>, <l> |
16b | Строка двухбайтовых символов переменной длины | WSTRING | " (пустая) | 16 <i>, <g>, <k>, <l> |
17a | Однобайтовый символ | CHAR | '$00' | 8 <g>, <l> |
17b | Двухбайтовый символ | WCHAR | "$0000" | 16 <g>, <l> |
18 | Битовая строка длины 8 | BYTE | 16#00 | 8 <j>, <g> |
19 | Битовая строка длины 16 | WORD | 16#0000 | 16 <j>, <g> |
20 | Битовая строка длины 32 | DWORD | 16#0000_0000 | 32 <j>, <g> |
21 | Битовая строка длины 64 | LWORD | 16#0000_0000_0000_0000 | 64 <j>, <g> |
Примечание - Определяется разработчиком, так как специальное стартовое значение отлично от 0001-01-01.
-------------------------------- <a> Значения в данной колонке интерпретируются как описано в подстрочных примечаниях к таблице. <b> Диапазон значений и точность представления в данных типах данных определяются разработчиком. <c> Диапазон значений переменных данного типа данных от -(2N-1) до (2N-1) - 1. <d> Диапазон значений переменных данного типа данных от 0 до (2N) - 1. <e> Диапазон значений переменных данного типа данных определяется в МЭК 60559 для основного формата с плавающей точкой одинарной точности. Результаты арифметических команд с ненормализованными значениями, бесконечным значением и нечисловыми значениями определяются разработчиком. <f> Значение переменных данного типа данных определяется в МЭК 60559 для основного формата с плавающей точкой двойной точности. Результаты арифметических команд с ненормализованными значениями, бесконечным значением и нечисловыми значениями определяются разработчиком. <g> Числовой диапазон значений не применяется к данному типу данных. <h> Возможные значения переменных этого типа данных: 0 и 1, соответствующие ключевым словам FALSE и TRUE соответственно. <i> Значение N указывает на число битов или символов для этого типа данных. <j> Значение N указывает на число битов в битовой строке для этого типа данных. <k> Допустимая переменных типов STRING и WSTRING определяется разработчиком. <l> Типов CHAR, STRING, WCHAR и WSTRING используется кодировка по ИСО/МЭК 10646 (см. 6.3.3). <m> Тип данных LTIME является 64-битовым целым числом со знаком, значение задается в наносекундах. <n> Тип данных LDATE является 64-битовым целым числом со знаком, значение задается в наносекундах, с начальной датой 1970-01-01. <p> Тип данных LTOD является 64-битовым целым числом со знаком, значение задается в наносекундах, начальное время с полуночи TOD#00:00:00. <q> Точность обновления значений данного формата времени определяется разработчиком; то есть значение указывается в наносекундах, но оно может обновляться через микросекунду или миллисекунду. |
6.4.2.2 Элементарные строковые типы данных (STRING, WSTRING)
Максимальная поддерживаемая длина элементов типа STRING и WSTRING задается разработчиком и определяет максимальную длину STRING и WSTRING, которая поддерживается средствами программирования и отладки.
Явная максимальная длина определяется максимальной длиной (которая не должна превышать поддерживаемое максимальное значение, определенное разработчиком), приведенной в скобках в соответствующем объявлении данных.
Доступ к отдельным символам строки в элементах данных CHAR или WCHAR осуществляется указанием в квадратных скобках позиции символа в строке, начиная с позиции 1.
Ошибка возникает, если к строкам двухбайтовых символов осуществляется доступ с использованием однобайтовых символов или если к строкам однобайтовых символов осуществляется доступ с использованием двухбайтовых символов.
Пример 1 - Типы STRING, WSTRING и CHAR, WCHAR
a) Объявление
VAR
String1: STRING[10]:= 'ABCD';
String2: STRING[10]:= ";
aWStrings: ARRAY [0..1] OF WSTRING:= ["1234", "5678"];
Char1: CHAR;
WChar1: WCHAR;
END_VAR
b) Использование типов STRING и CHAR
Char1:= String1[2]; // эквивалентно Char1:= 'B';
String1[3]:= Char1; // приводит к String1:= 'ABBD'
String1[4]:= 'B'; // приводит к String1:= 'ABBB'
String1[1]:= String1[4]; // приводит к String1:= 'BBBB'
String2:= String1[2]; (* приводит к String1:= 'BBBB'
если было выполнено неявное преобразование CHAR_TO_STRING*)
c) Использование типов WSTRING и WCHAR
WChar1:= aWStrings[1][2]; // эквивалентно WChar1:= 'B';
aWStrings[1][3]:= WChar1; // приводит к aWStrings[1]:= "5668"
aWStrings[1][4]:= "6"; // приводит к aWStrings[1]:= "5666"
WStrings[1][1]:= aWStrings[1][4]; // приводит к String1:= "6666"
aWStrings[0]:= aWStrings[1][4]; (* приводит aWStrings[0]:= "6";
если было выполнено неявное преобразование WCHAR_TO_WSTRING*)
d) Эквивалентные функции (см. 6.6.2.5.11)
Char1:= String1[2];
эквивалентно
Char1:= STRING_TO_CHAR(Mid(IN:= String1, L:= 1, P:= 2));
aWStrings[1][3]:= WChar1;
эквивалентно
REPLACE(IN1:= aWStrings[1], IN2:= WChar1, L:= 1, P:= 3);
e) Случаи ошибки
Char1:= String1[2]; // смешивание типов WCHAR,
STRING String1[2]:= String2;
// требует неявного преобразования STRING_TO_CHAR, которое не разрешено
Примечание - Типы данных для отдельных символов (CHAR и WCHAR) могут содержать только один символ. Строки могут содержать несколько символов; поэтому строки могут содержать дополнительную информацию для управления, которая не нужна для отдельных символов.
Пример 2 - Если тип STR10 объявлен как
TYPE STR10: STRING[10]:='ABCDEF'; END_TYPE,
то максимальная длина STR10 равна 10 символам, начальное значение по умолчанию равно 'ABCDEF', и начальная длина элементов данных типа STR10 равна шести символам.
6.4.3 Родовые типы данных
В дополнение к элементарным типам данных, приведенным в таблице 10, в спецификации входных и выходных переменных стандартных функций и функциональных блоков можно использовать иерархию родовых типов данных, показанных на рисунке 5. Родовые типы данных определяются по префиксу "ANY".
При использовании родовых типов данных следует соблюдать следующие правила:
1 Родовой тип прямо порожденного типа является таким же, как родовой тип элементарного типа, из которого он порожден.
2 Порожденным типом типа-диапазона является ANY_INT.
Родовым типом всех других порожденных типов, приведенных в таблице 11, является ANY_DERIVED.
Использование родовых типов данных в определенных пользователем программных компонентов находится вне области действия настоящего стандарта.
Родовые типы данных | Родовые типы данных | Группы элементарных типов данных | ||||
ANY | g) | |||||
| ANY_DERIVED | |||||
ANY_ELEMENTARY | ||||||
| ANY_MAGNITUDE | |||||
| ANY_NUM | |||||
| ANY_REAL | h) | REAL, LREAL | |||
ANY_INT | ANY_UNSIGNED | USINT, UINT, UDINT, ULINT | ||||
| ANY_SIGNED | SINT, INT, DINT, LINT | ||||
| ANY_DURATION |
| TIME, LTIME | |||
ANY_BIT |
| BOOL, BYTE, WORD, DWORD, LWORD | ||||
ANY_CHARS |
|
| ||||
| ANY_STRING |
| STRING, WSTRING | |||
ANY_CHAR |
| CHAR, WCHAR | ||||
ANY_DATE |
| DATE_AND_TIME, LDT, DATE, TIME_OF_DAY, LTOD | ||||
Рисунок 5 - Иерархия родовых типов данных
6.4.4 Определенные пользователем типы данных
6.4.4.1 Объявление (TYPE)
6.4.4.1.1 Общие положения
Назначение определенных пользователем типов данных - это их использование в объявлении других типов данных и в объявлениях переменных.
Определенный пользователем тип данных может использоваться везде, где может использоваться базовый тип.
Определенные пользователем типы данных объявляются, используя текстовую конструкцию TYPE...END_TYPE. Объявление типа состоит из следующих элементов:
- имя типа;
- символ двоеточия ":";
- объявление собственно типа, как определено в следующих предложениях.
Пример - Объявление типа
TYPE
myDatatype1: <объявление типа с необязательной инициализацией>;
END_TYPE
6.4.4.1.2 Инициализация
Определенные пользователем типы данных могут быть инициализированы определенными пользователем значениями. Такая инициализация имеет приоритет над неявным начальным значением.
Определенная пользователем инициализация следует за объявлением типа и начинается оператором присваивания ":=", за которым следует начальное значение (значения).
Могут использоваться литералы (например, -123, 1.55, "abc") или константные выражения (например, 12*24). Используемые начальные значения должны иметь совместимый тип, то есть тот же самый тип или тип, который может быть конвертирован, используя неявное преобразование типа.
Для инициализации типов данных следует применять правила, приведенные на рисунке 6.
Родовой тип данных | Инициализировано литералом | Результат |
ANY_UNSIGNED | Неотрицательный целый литерал или неотрицательное константное выражение | Неотрицательное целое значение |
ANY_SIGNED | Целый литерал или константное выражение | Целое значение |
ANY_REAL | Числовой литерал или константное выражение | Числовое значение |
ANY_BIT | Целый литерал без знака или константное выражение без знака | Целое значение без знака |
ANY_STRING | Битово-строковый литерал | Строковое значение |
ANY_DATE | Литерал даты и времени суток | Значение даты и времени суток |
ANY_DURATION | Литерал продолжительности времени | Значение продолжительности времени |
Рисунок 6 - Инициализация литералами и константными
выражениями (правила)
В таблице 11 определены свойства объявления типов данных и их инициализации, определенных пользователем.
Таблица 11
Объявление определенных пользователем типов данных и их
инициализации
Номер | Описание | Пример | Объяснение | ||
1a 1b | Перечислимые типы данных | TYPE ANALOG_SIGNAL_RANGE: (BIPOLAR_10V, UNIPOLAR_10V, UNIPOLAR_1_5V, UNIPOLAR_0_5V, UNIPOLAR_4_20_MA, UNIPOLAR_0_20_MA) |
| ||
:= UNIPOLAR_1_5V; END_TYPE | Инициализация | ||||
2a 2b | Типы данных с именованными значениями | TYPE Colors: DWORD (Red := 16#00FF0000, Green:= 16#0000FF00, Blue := 16#000000FF, White:= Red OR Green OR Blue, Black:= Red AND Green AND Blue) |
| ||
:= Green; END_TYPE | Инициализация | ||||
3a 3b | Тип - диапазоны | TYPE ANALOG_DATA: INT(-4095 .. 4095):= 0; END_TYPE |
| ||
4a 4b | Типы данных - массивы | TYPE ANALOG_16_INPUT_DATA: ARRAY [1.. 16] OF ANALOG_DATA | ANALOG_DATA см. выше. | ||
:= [8(-4095), 8(4095)]; END_TYPE | Инициализация | ||||
5a 5b | Типы функциональных блоков и классы как элементы массива | TYPE TONs: ARRAY[1..50] OF TON := [50(PT:=T#100ms)]; END_TYPE | Инициализация функционального блока TON как элемента массива | ||
6a 6b | Структурированный тип данных | TYPE ANALOG_CHANNEL_CONFIGURATION: STRUCT RANGE: ANALOG_SIGNAL_RANGE; MIN_SCALE: ANALOG_DATA:= -4095; MAX_SCALE: ANALOG_DATA:=4095; END_STRUCT; END_TYPE | см. выше ANALOG_SIGNAL_RANGE | ||
7a 7b | Типы функциональных блоков и классы как элементы структуры | TYPE Cooler: STRUCT Temp: INT; Cooling: TOF:= (PT:=T#100ms); END_TYPE | Функциональный блок TOF как элемент структуры | ||
8a 8b | Структурированный тип данных с относительной адресацией AT | TYPE Com1_data: STRUCT | Явное расположение без перекрытия | ||
head | AT %B0: | INT; | |||
length | AT %B2: | USINT:= 26; | |||
flag1 | AT %X3.0: | BOOL; | |||
end | AT %B25: | BYTE; | |||
END_STRUCT; END_TYPE | |||||
9a | Структурированный тип данных с относительной адресацией AT и OVERLAP | TYPE Com2_data: STRUCT OVERLAP | Явное расположение с перекрытием | ||
head | AT %B0: | INT; | |||
length | AT %B2: | USINT; | |||
flag2 | AT %X3.3: | BOOL; | |||
data1 | AT %B5: | BYTE; | |||
data2 | AT %B5: | REAL; | |||
end | AT %B19: | BYTE; | |||
END_STRUCT; END_TYPE | |||||
10a 10b | Прямо представленные элементы структуры - частично определенные, используя "*" | TYPE HW_COMP: STRUCT; IN AT %I*: BOOL; OUT_VAR AT %Q*: WORD:= 200; ITNL_VAR: REAL:= 123.0; // not located END_STRUCT; END_TYPE | Присваивает компоненты структуры еще не локализованным входным и выходным переменным, см. примечание 2 | ||
11a 11b | Прямо производный тип данных | TYPE CNT: UINT; FREQ: REAL:= 50.0; ANALOG_CHANNEL_CONFIG: | Инициализация | ||
ANALOG_CHANNEL_CONFIGURATION := (MIN_SCALE:= 0, MAX_SCALE:= 4000); END_TYPE | Новая инициализация | ||||
12 | Инициализация с использованием константных выражений | TYPE PIx2: REAL:= 2 * 3.1416; END_TYPE | Использует константное выражение | ||
Примечание 1 - Возможно объявление типа данных без инициализации (свойство "a") или с инициализацией (свойство "b"). Если поддерживается свойство "a", тип данных инициализируется с неявным начальным значением. Если поддерживается свойство "b", тип данных инициализируется с данным значением или неявным начальным значением, если начальное значение не дано. Примечание 2 - Переменные с прямо представленными элементами - частично определенными, используя "*", не могут использоваться в секциях VAR_INPUT или VAR_IN_OUT. |
6.4.4.2 Перечислимый тип данных
6.4.4.2.1 Общие положения
Объявление перечислимого типа данных означает, что каждый элемент данных этого типа может принимать только значения, указанные в соответствующем перечне идентификатора, как показано в таблице 11.
Перечень перечисления определяет упорядоченное множество перечислимых значений, начиная с первого идентификатора и оканчивая последним.
Различные перечислимые типы данных могут использовать одинаковые идентификаторы для перечислимых значений. Максимально допустимое число перечислимых значений определяется разработчиком.
Для обеспечения уникальной идентификации при использовании в конкретном контексте, перечислимые литералы могут уточняться префиксом, состоящим из имени ассоциированного типа данных и символа номера "#", аналогично типизированным литералам. В перечне перечисления префиксы не используются.
Происходит ошибка, если в перечислимом литерале недостаточно информации для однозначного определения его значения (см. пример ниже).
Пример - Перечислимый тип данных
TYPE
Traffic_light: (Red, Amber, Green);
Painting_colors: (Red, Yellow, Green, Blue):= Blue;
END_TYPE
VAR
My_Traffic_light: Traffic_light:= Red;
END_VAR
IF My_Traffic_light = Traffic_light#Amber THEN ... // OK
IF My_Traffic_light = Traffic_light#Red THEN ... // OK
IF My_Traffic_light = Amber THEN ... // OK - идентификатор Amber уникален
IF My_Traffic_light = Red THEN ... // ОШИБКА - идентификатор Red не является уникальным
6.4.4.2.2 Инициализация
Неявное начальное значение перечислимого типа данных - первый идентификатор в связанном перечне перечисления.
Пользователь может инициализировать тип данных определенным пользователем значением из перечня перечислимых значений данного типа. Такая инициализация имеет приоритет.
Как показано в таблице 11 для ANALOG_SIGNAL_RANGE, определенное пользователем начальное значение перечислимого типа данных - это присвоенное значение UNIPOLAR_1_5V.
Определенное пользователем присваивание начального значения типа данных является свойством в таблице 11.
6.4.4.3 Тип данных с именованными значениями
6.4.4.3.1 Общие положения
Связанным с перечислимым типом данных, где перечислимые идентификаторы не заданы пользователем, является перечислимый тип данных с именованными значениями. Объявление определяет тип данных и присваивает значения именованных переменных, как показано в таблице 11.
Объявление именованных значений не ограничивает диапазон значений переменных этого типа, то есть переменной могут быть присвоены другие константы, или значение может определяться вычислением.
Для обеспечения уникальной идентификации при использовании в конкретном контексте, именованные значения могут уточняться префиксом, состоящим из имени ассоциированного типа данных и символа номера "#", аналогично типизированным литералам.
В перечне объявления префиксы не используются. Происходит ошибка, если в перечислимом литерале недостаточно информации для однозначного определения его значения (см. пример).
Пример - Тип данных с именованными значениями
TYPE
Traffic_light: INT (Red:= 1, Amber:= 2, Green:= 3):= Green;
Painting_colors: INT (Red:= 1, Yellow:= 2, Green:= 3, Blue:= 4):= Blue;
END_TYPE
VAR
My_Traffic_light: Traffic_light;
END_VAR
My_Traffic_light:= 27; // Присваивание константы IF
My_Traffic_light = Amber THEN ...// Присваивание выражения
// Примечание - Это невозможно для перечислимых значений
My_Traffic_light:= Traffic_light#Red + 1;
IF My_Traffic_light = 123 THEN... // OK
IF My_Traffic_light = Traffic_light#Amber THEN ... // OK
IF My_Traffic_light = Traffic_light#Red THEN ... // OK
IF My_Traffic_light = Amber THEN ... // OK - идентификатор Amber
уникален
IF My_Traffic_light = Red THEN ... // ОШИБКА - идентификатор
Red не является уникальным
6.4.4.3.2 Инициализация
Неявное значение для типа данных с именованными значениями - это первый элемент данных в перечне перечисления. В приведенном выше примере для Traffic_light таким элементом является Red.
Пользователь может инициализировать тип данных определенным пользователем значением. Инициализация не ограничивается именованными значениями - может использоваться любое значение из диапазона базового типа. Такая инициализация имеет приоритет.
В пример, определенным пользователем начальным значением перечислимого типа для Traffic_light является Green.
Определенное пользователем присваивание начального значения типа данных является свойством в таблице 11.
6.4.4.4 Тип-диапазон
6.4.4.4.1 Общие положения
Декларацией типа-диапазона определено, что значение любого элемента данных этого типа может принимать значения между указанными верхними и нижними пределами (включительно), как показано в таблице 11.
Пределы в типе-диапазоне должны быть литералами или константными выражениями.
Пример -
TYPE
ANALOG_DATA: INT(-4095 .. 4095):= 0;
END_TYPE
6.4.4.4.2 Инициализация
Неявные начальные значения для типов данных с диапазоном - это первый (нижний) предел диапазона.
Пользователь может инициализировать тип данных определенным пользователем значением из диапазона. Такая инициализация имеет приоритет.
Например, как показано в примере, приведенном в таблице 11, неявное начальное значение элементов типа ANALOG_DATA равно -4095, в то время, как при явной инициализации, неявное начальное значение равно нулю (как объявлено).
6.4.4.5 Типы данных - массивы
6.4.4.5.1 Общие положения
Объявление типа данных - массива определяет, что должно быть выделено достаточное количество памяти для каждого элемента этого типа, чтобы хранить все данные, которые могут быть индексированы указанным поддиапазоном (поддиапазонами) индексов, как показано в таблице 11.
Массив - это совокупность элементов данных одинакового типа. В качестве типа элемента массива могут использоваться элементарные и определенные пользователем типы данных, типы функциональных блоков и классы. На данную совокупность элементов данных ссылаются с помощью одного или более индексов, заключенных в квадратные скобки и разделенных запятыми. Если значение индекса выходит за пределы, указанные в объявлении массива, возникает ошибка.
Примечание - Для вычисляемых индексов такая ошибка может быть обнаружена только во время выполнения.
Максимальное число индексов массива, максимальный размер массива и максимальный диапазон значений индекса определяются разработчиком.
Пределы в диапазона индекса должны быть литералами или константными выражениями. Массивы переменной длины определены в 6.5.3.
В языке ST индекс является выражением, производящим значение, соответствующее одному из подтипов родового типа ANY_INT.
Форма индексов в языке IL и графических языках, определенных в разделе 8, ограничена одноэлементными переменными или целыми литералами.
Пример -
a) Объявление массива
VAR myANALOG_16: ARRAY [1..16] OF ANALOG_DATA;
:= [8(-4095), 8(4095)]; // определенные пользователем начальные значения
END_VAR
b) Использование переменных массива в языке ST может быть следующим:
OUTARY[6,SYM]:= INARY[0] + INARY[7] - INARY[i] * %IW62.
6.4.4.5.2 Инициализация
Неявное начальное значение каждого элемента массива - это начальное значение, определенное для типа данных элементов массива.
Пользователь может инициализировать тип массива значением, определенным пользователем. Такая инициализация имеет приоритет.
Определенное пользователем начальное значение массива назначается в форме списка, в котором могут использоваться скобки для обозначения повторений.
Во время инициализации типов данных - массивов, самый правый индекс массива изменяется быстрее остальных при наполнении массива из списка начальных значений.
Пример - Инициализация массива
A: ARRAY [0..5] OF INT:= [2(1, 2, 3)]
эквивалентно последовательности инициализации 1, 2, 3, 1, 2, 3.
Если число начальных значений, данных в перечне инициализации превышает число входов массива, лишние (самые правые начальные значения будут отброшены. Если число начальных значений меньше, чем число входов массива, оставшиеся входы массива будут заполнены неявными начальными значениями для соответствующего типа данных. В любом случае, пользователь будет предупрежден об этой ситуации во время подготовки программы для выполнения.
Определенное пользователем присваивание начального значения типа данных является свойством в таблице 11.
6.4.4.6 Структурированный тип данных
6.4.4.6.1 Общие положения
Объявление структурированного типа данных (STRUCT) указывает, что этот тип данных содержит совокупность подэлементов определенных типов, к которым можно осуществлять доступ под определенным именем, как показано в таблице 11.
Элемент структурированного типа данных представляется двумя или более идентификаторами, разделенными точкой ".".
Первый идентификатор представляет имя структурированного элемента, а последующие идентификаторы представляют последовательность имен элементов для доступа к конкретному элементу данных в структуре данных.
В качестве типа элемента структуры могут использоваться элементарные и определенные пользователем типы данных, типы функциональных блоков и классы.
Например, элемент типа данных ANALOG_CHANNEL_CONFIGURATION, объявленный таблице 11, будет содержать подэлемент RANGE типа ANALOG_SIGNAL_RANGE, подэлемент MIN_SCALE типа ANALOG_DATA и подэлемент MAX_SCALE типа ANALOG_DATA.
Максимальное число элементов структуры, максимальное количество данных, которое может содержаться в структуре и максимальное число вложенных уровней адресации структурного элемента определяются разработчиком.
Две структурированных переменных являются совместимыми по присваиванию, только если они имеют одинаковый тип данных.
Пример - Объявление и использование структурированного типа данных и структурированной переменной.
a) Объявление структурированного типа данных
TYPE
ANALOG_SIGNAL_RANGE: (BIPOLAR_10V,
UNIPOLAR_10V);
ANALOG_DATA: INT (-4095 .. 4095);
ANALOG_CHANNEL_CONFIGURATION:
STRUCT
RANGE: ANALOG_SIGNAL_RANGE;
MIN_SCALE: ANALOG_DATA:
MAX_SCALE: ANALOG_DATA;
END_STRUCT;
END_TYPE
b) Объявление структурированной переменной
VAR
MODULE_CONFIG:ANALOG_CHANNEL_CONFIGURATION;
MODULE_8_CONF: ARRAY [1..8] OF ANALOG_CHANNEL_CONFIGURATION;
END_VAR
c) Использование переменных массива в языке ST:
MODULE_CONFIG.MIN_SCALE:= -2047;
MODULE_8_CONF[5].RANGE:= BIPOLAR_10V.
6.4.4.6.2 Инициализация
Неявные значения компонентов структуры даются их индивидуальными типами данных.
Пользователь может инициализировать компоненты структуры значениями, определенными пользователем. Такая инициализация имеет приоритет.
Пользователь может также инициализировать ранее определенную структуру, используя перечень присваиваний компонентам структуры. Данная инициализация имеет более высокий приоритет, чем неявная инициализация и инициализация компонентов.
Пример - Инициализация структуры
a) Объявление с инициализацией структурированного типа данных
TYPE
ANALOG_SIGNAL_RANGE:
(BIPOLAR_10V,
UNIPOLAR_10V):= UNIPOLAR_10V;
ANALOG_DATA: INT (-4095 ..4095);
ANALOG_CHANNEL_CONFIGURATION;
STRUCT
RANGE: ANALOG_SIGNAL_RANGE;
MIN_SCALE: ANALOG_DATA:= -4095;
MAX_SCALE: ANALOG_DATA:= -4096;
END_STRUCT;
ANALOG_8BI_CONFIGURATION:
ARRAY [1..8] OF ANALOG_CHANNEL_CONFIGURATION
:= [8((RANGE:= BIPOLAR_10V))];
END_TYPE
b) Объявление с инициализацией структурированной переменной
VAR
MODULE_CONFIG:ANALOG_CHANNEL_CONFIGURATION
:= (RANGE:= BIPOLAR_10V, MIN_SCALE:= -1023);
MODULE_8_SMALL: ANALOG_8BI_CONFIGURATION
:= [8 ((MIN_SCALE:= -2047, MAX_SCALE:= 2048))];
END_VAR
6.4.4.7 Относительное положение элементов структурированных типов данных (AT)
6.4.4.7.1 Общие положения
Положения (адреса) элементов структурированного типа могут быть определены относительно начала структуры.
В этом случае, за именем компонента этой структуры следует ключевое слово AT и относительный адрес.
Объявление может содержать разрывы в расположении памяти.
Относительный адрес состоит из символа процента "%", определителя битового или байтового адреса. Байтовый адрес - это целый литерал без знака, обозначающий смещение в байтах. Битовый адрес состоит из смещения в байтах, следующего символа точки "." и смещения в битах, являющегося целым литералом без знака в диапазоне от 0 до 7. В относительном адресе не допускаются пробельные символы.
Компоненты структуры не должны перекрываться в расположении памяти, за исключением ситуации, когда в объявлении имеется ключевое слово OVERLAP.
Перекрытие строк находится вне области применения настоящего стандарта.
Примечание - Отсчет битового смещения начинается от самого правого бита с 0. Отсчет битового смещения начинается от начала структуры с 0.
Пример - Относительные адреса и перекрытие в структуре
TYPE
Com1_data: STRUCT
head AT %B0: INT; // в положении 0
length AT %B2: USINT=26; // в положении 2
flag1 AT %X3.0: BOOL; // в положении 3.0
end AT %B25: BYTE; // в положении 25, оставляя разрыв
END_STRUCT;
Com2_data: STRUCT OVERLAP
head AT %B0: INT; // в положении 0
length AT %B2: USINT; // в положении 2
flag2 AT %X3.3: BOOL; // в положении 3.3
data1 AT %B5: BYTE; // в положении 5, перекрывается
data2 AT %B5: REAL; // в положении от 5 до 8
end AT %B19: BYTE; // по адресу 19, оставляя разрыв
END_STRUCT;
Com_data: STRUCT OVERLAP // C1 и C2 перекрываются
C1 at %B0: Com1_data:
C2 at %B0: Com2_data;
END_STRUCT;
END_TYPE
6.4.4.7.2 Инициализация
Структуры с перекрытием не могут явно инициализироваться.
6.4.4.8 Прямо представленные компоненты структуры - частично определенные с использованием "*"
Символ звездочки "*" в таблице 11 может использоваться, чтобы обозначить еще не полностью определенные адреса для прямо представленных компонентов структуры.
Пример - Присваивание компонентов структуры еще не локализованным входным и выходным переменным.
TYPE
HW_COMP: STRUCT;
IN AT %I*; BOOL;
VAL AT %I*; DWORD;
OUT AT %Q*: BOOL; OUT_VAR AT %Q*: WORD;
ITNL_VAR: REAL; // еще не локализован END_STRUCT;
END_TYPE
В случае, когда прямо представленный компонент структуры используется для назначения расположения в части объявлений программы, типа функционального блока или класса, на месте префикса размера и целого со знаком может использоваться звездочка "*" для указания того, что прямое представление еще не полностью определено.
Использование этого свойства требует, чтобы положение структурированной переменной, объявленной таким образом, было полностью определено внутри конструкции VAR_CONFIG...END_VAR конфигурации для каждого экземпляра охватывающего типа.
Переменные такого типа не могут использоваться в секциях VAR_INPUT, VAR_IN_OUT и VAR_TEMP.
Ошибка возникает, если отсутствует какая-либо полная спецификация в конструкции VAR_CONFIG...END_VAR для какой-либо неполной спецификации адреса, выраженной символом "*" в любом экземпляре программы или функционального блока, который содержит такие неполные спецификации.
6.4.4.9 Прямо порожденный тип данных
6.4.4.9.1 Общие положения
Определенные пользователем типы данных могут быть прямо порождены из элементарного типа данных или определенного пользователем типа данных.
Это может быть использовано для определения специфических для типа начальных значений.
Пример - Прямо порожденный тип данных
TYPE
myInt1123: INT:= 123;
myNewArrayType: ANALOG_16_INPUT_DATA:= [8(-1023), 8(1023)];
Com3_data: Com2_data:= (head:= 3, length:=40);
END_TYPE
.R1: REAL:= 1.0;
R2: R1;
6.4.4.9.2 Инициализация
Неявное начальное значение равно начальному значению типа данных, из которого порожден новый тип. Пользователь может инициализировать тип данных определенным пользователем значением. Такая инициализация имеет приоритет.
Определенное пользователем начальное значение элементов структуры может быть объявлено в перечне, заключенном в скобки и следующим за идентификатором типа данных. Элементы, начальное значение которых не перечислено в перечне инициализации, имеют неявные начальные значения, объявленные для них в объявлении оригинального типа данных.
Пример 1 - Использование определенных пользователем типов данных
С учетом объявлений ANALOG_16_INPUT_DATA в таблице 11 и объявления VAR INS: ANALOG_16_INPUT_DATA; END_VAR переменные от INS[1] до INS[16] могут использоваться везде, где могут использоваться переменные типа INT.
Пример 2
Аналогично, с учетом объявления Com_data в таблице 11 и, дополнительно, объявления VAR telegram: Com_data; END_VAR переменная telegram.length может использоваться везде, где может использоваться тип USINT.
Пример 3
Это правило может применяться рекурсивно:
С учетом объявления ANALOG_16_INPUT_CONFIGURATION, ANALOG_CHANNEL_CONFIGURATION и ANALOG_DATA в таблице 11 и объявления VAR CONF: ANALOG_16_INPUT_CONFIGURATION; END_VAR переменная CONF.CHANNEL[2].MIN_SCALE может использоваться везде, где может использоваться тип INT.
6.4.4.10 Указатели
6.4.4.10.1 Объявление указателя
Указатель - это переменная, которая содержит только ссылку на переменную или на экземпляр функционального блока. Указатель может иметь значение NULL, то есть он не ссылается ни на что.
Указатели объявляются для определенных типов данных, используя ключевое слово REF_TO и ссылочный тип данных - тип данных, на который производится ссылка. Ссылочный тип данных уже должен быть определен. Им может являться элементарный тип данных или определенный пользователем тип данных.
Примечание - Указатели без привязки к типу данных выходят за пределы настоящего стандарта.
Пример 1
TYPE
myArrayType: ARRAY[0..999] OF INT;
myRefArrType: REF_TO myArrayType; // определение указателя
myArrOfRefType: ARRAY [0..12] OF myRefArrType; // определение массива ссылок
END_TYPE
VAR
myArray1: myArrayType;
myRefArr1: myRefArrType; // определение указателя
myArrOfRef: myArrOfRefType; // определение массива указателей
END_VAR
Ссылка должна ссылаться только на переменные указанного ссылочного типа данных. Указатели на прямо порождаемые типы данных обрабатываются как псевдонимы указателей на базовый тип данных. Прямое порождение может применяться несколько раз.
Пример 2
TYPE
myArrType1: ARRAY[0..999] OF INT;
myArrType2: myArrType1;
myRefType1: REF_TO myArrType1;
myRefType2: REF_TO myArrType2;
END_TYPE
myRefType1 и myRefType2 могут ссылаться на переменные типа ARRAY[0..999] OF INT и производных типов данных.
Ссылочный тип данных указателя может также являться типом функционального блока или классом. Указатель базового типа может также ссылаться на экземпляры, порожденные из этого типа данных.
Пример 3
CLASS F1 ... END_CLASS;
CLASS F2 EXTENDS F1 ... END_CLASS;
TYPE
myRefF1: REF_TO F1;
myRefF2: REF_TO F2;
END_TYPE
Указатели типа myRefF1 могут ссылаться на экземпляры классов F1, F2 и на производные от них классы. Однако указатели типа myRefF2 не могут ссылаться на экземпляры класса F1, а могут ссылаться только на экземпляры класса F2 и производные от него, так как класс F1 может не поддерживать методы и переменные расширенного класса F2.
6.4.4.10.2 Инициализация указателей
Указатели могут инициализироваться значением NULL (неявно) или адресом уже объявленных переменных, экземпляров функционального блока или класса.
Пример -
FUNCTION_BLOCK F1 ... END_FUNCTION_BLOCK;
VAR
myInt: INT;
myRefInt: REF_TO INT:= REF(myInt);
myF1: F1;
myRefF1: REF_TO F1:= REF(myF1);
END_VAR
6.4.4.10.3 Операции с указателями
Оператор REF() возвращает указатель на заданную переменную или экземпляр. Ссылочным типом данных возвращенного указателя является тип данных заданной переменной. Применение оператора REF() к временной переменной (например, переменным любой секции VAR_TEMP или любым переменным внутри функций) не разрешается.
Указатель может быть присвоен другому указателю, если его ссылочный тип данных эквивалентен базовому типу или является ссылочным типом данных присвоенного указателя.
Указатели могут присваиваться параметрам функций, функциональных блоков и методов в вызове, если ссылочный тип данных параметра эквивалентен базовому типу или является базовым типом ссылочного типа данных. Ссылки не могут использоваться как входные-выходные переменные.
Если указатель присвоен указателю такого же типа данных, то последний ссылается на ту же самую переменную. В таком случае, прямо порожденный тип данных рассматривается так же, как его базовый тип.
Если указатель присваивается указателю на такой же тип функционального блока или базовый тип функционального блока, то затем этот указатель указывает на тот же самый экземпляр, но является все еще связанным со своим типом функционального блока, то есть может использовать только переменные и методы своего ссылочного типа данных.
Разыменование указателей осуществляется явно.
Указатель разыменовывается использованием предшествующего символа крышки .
Разыменованный указатель может использоваться так же, как прямо используется переменная. Разыменованный указатель на NULL является ошибкой.
Примечание 1 - Возможные проверки указателей на NULL может производиться во время компиляции, системой поддержки выполнения программы или прикладной программой.
Конструкция REF() и оператор разыменования используются в графических языках при определении операндов.
Примечание 2 - Арифметические операции с указателями не рекомендуются и не входят в задачу настоящего стандарта.
Пример 1
TYPE
S1: STRUCT
SC1: INT;
SC2: REAL;
END_STRUCT;
A1: ARRAY[1..99] OF INT;
END_TYPE
VAR
myS1: S1;
myA1: A1;
myRefS1: REF_TO S1:= REF(myS1);
myRefA1: REF_TO A1:= REF(myA1);
myRefInt: REF_TO INT:= REF(myA1[1]);
END_VAR
myRefS1.SC1:= myRefA1
[12]; // в данном случае, это эквивалентно S1.SC1:= A1[12];
myRefInt:= REF(A1[11]);
S1.SC1:= myRefInt; // присваивает значение переменной A1[11] элементу структуры S1.SC1
Пример 2
Графическое представление операторов из примера 1
В таблице 12 приведены свойства операций с указателями.
Таблица 12
Операции с указателями
Номер | Описание | Пример |
| Объявление |
|
1 | // определение типа указателя | TYPE myRefType: REF_TO INT; END_TYPE |
| Присваивание и сравнение |
|
2a | Присваивание указателя указателю | <указатель>:= <указатель> myRefType1:= myRefType2; |
2b | Присваивание указателя параметру функции, функционального блока или метода | myFB (a:= myRefS1); Типы должны быть эквивалентными |
2c | Сравнение с NULL | IF myInt = NULL THEN ... |
| Создание ссылки |
|
3a | REF (<переменная>) Предоставляет типизированную ссылку на переменную | myRefA1:= REF (A1); |
3b | REF (<экземпляр функционального блока>) Предоставляет типизированную ссылку на экземпляр функционального блока или класса | myRefFB1:= REF(myFB1) |
| Разыменование |
|
4 | <указатель> Предоставляет содержимое переменной или содержимое экземпляра, на которые ссылается переменная указателя | myInt:= myA1Ref |