#plc #twincat #codesys #st #iec61131-3
Вопрос:
Я пытаюсь назначить два инициализированных массива evenNumbers
и oddNumbers
массиву массивов integers
:
PROGRAM ArrayInit
VAR
evenNumbers : ARRAY[1..3] OF INT := [2, 4, 6];
oddNumbers: ARRAY[1..3] OF INT := [1, 3, 5];
integers : ARRAY[1..2] OF ARRAY[1..3] OF INT := [evenNumbers, oddNumbers];
END_VAR
Этот код выдает мне ошибку компилятора
Ожидается инициализация массива
Конечно, я могу напрямую инициализировать integers
числа, которые я хочу, вот так:
PROGRAM ArrayInit
VAR
integers: ARRAY[1..2] OF ARRAY[1..3] OF INT := [
[2, 4, 6], [1, 3, 5]
];
END_VAR
или как упоминал Сергей
PROGRAM ArrayInit
VAR
integers: ARRAY[1..2, 1..3] OF INT := [
2, 4, 6, 1, 3, 5
];
END_VAR
Однако, если исходные массивы очень большие и/или я хочу задокументировать, что представляют собой эти разные массивы, было бы неплохо использовать описательное имя. Т. Е. integers : ARRAY[1..2] OF ARRAY[1..3] OF INT := [evenNumbers, oddNumbers];
хорошо видно, что в integers
нем есть два списка, один с четными и один с нечетными числами.
Я также пытался инициализировать integers
как integers: ARRAY[1..2] OF ARRAY[1..3] OF INT := [[evenNumbers], [oddNumbers]];
, но это приводит к ошибке компилятора:
Не удается преобразовать тип «МАССИВ [1..3] INT» в тип «INT»
Теперь я задаюсь вопросом, возможно ли это вообще? Если да, то кто-нибудь знает, как я могу это сделать?
Ответ №1:
Чтобы назначить массив с несколькими уровнями, вы делаете это в одной строке.
combinedSet : ARRAY[1..2, 1..2] OF INT := [1,2,3,4];
приведет к массиву
[
1 => [
1 => 1,
2 => 2
],
2 => [
1 => 2,
2 => 4
]
]
ПОЭТОМУ сначала он назначает все элементы первого элемента [1, 1]
, [1, 2]
, [1, 3]
… а потом гнездо одно [2, 1]
, [2, 2]
, [2, 3]
…
Дополнительная информация
Самый простой способ объединить 2 массива в один многомерный-это:
PROGRAM PLC_PRG
VAR
arr1 : ARRAY[1..3] OF INT := [1,3,5];
arr2 : ARRAY[1..3] OF INT := [2,4,6];
combinedSet : ARRAY[1..2] OF ARRAY[1..3] OF INT;
END_VAR
combinedSet[1] := arr1;
combinedSet[2] := arr2;
END_PROGRAM
Причина, по которой это не работает
integers : ARRAY[1..2] OF ARRAY[1..3] OF INT := [evenNumbers, oddNumbers];
Потому evenNumbers
что и oddNumbers
не инициализируются в момент использования. Если бы вы объявили их в VAR CONSTANT
нем, это, вероятно, сработало бы, но тогда вы не смогли бы изменить содержимое этих массивов в программе.
Комментарии:
1. Спасибо, Сергей. К сожалению, это не совсем то, что я искал. Я обновил вопрос, чтобы прояснить его, надеюсь. Мне было интересно , можно ли будет повторно использовать инициализированные массивы
oddNumbers
иevenNumbers
, чтобы было понятнее, что хранится в новом массивеintegers
.2. Я добавил несколько дополнительных ответов. Более сложный способ объединения массивов с помощью выделения памяти @Guiorgy уже опубликовал.
3. Ввод
evenNumbers
иoddNumbers
ввод, кVAR_GLOBAL CONSTANT
сожалению, не работает. Назначение их в самой программе (combinedSet[1] := arr1;
) — это также то, к чему я пришел в определенный момент. Я надеялся, что это можно сделать непосредственно в декларации, но, к сожалению, похоже, что это не так.
Ответ №2:
Я не думаю, что вы можете присоединяться к массивам при инициализации третьего (см. правку ниже). Однако вы можете вызвать функцию в начале программы, как только она соединит эти два массива:
PROGRAM PLC_PRG
VAR
arr1: ARRAY [0..2] OF INT := [1, 2, 3];
arr2: ARRAY [0..2] OF INT := [4, 5, 6];
arr3: ARRAY [0..5] OF INT;
initialized: BOOL := FALSE;
END_VAR
IF (NOT initialized) THEN
initialized := TRUE;
JOIN_INT_ARRAYS(arr1 := arr1, arr2 := arr2, dest_arr := arr3);
END_IF
// Assume that:
// - the destination ARRAY size can fit all source ARRAYs
// - all ARRAYs store INTs
FUNCTION JOIN_INT_ARRAYS
VAR CONSTANT
size_of_int: DWORD := SIZEOF(INT);
END_VAR
VAR_IN_OUT
arr1: ARRAY [*] OF INT;
arr2: ARRAY [*] OF INT;
dest_arr: ARRAY [*] OF INT;
END_VAR
VAR
arr1_len: DWORD := DINT_TO_DWORD(UPPER_BOUND(arr1, 1) - LOWER_BOUND(arr1, 1) 1) * size_of_int;
END_VAR
MEMUtils.MemCpy(pbySrc := arr1, pbyDest := dest_arr, dwSize := arr1_len);
MEMUtils.MemCpy(pbySrc := arr2, pbyDest := dest_arr arr1_len, dwSize := DINT_TO_DWORD(UPPER_BOUND(arr2, 1) - LOWER_BOUND(arr2, 1) 1) * size_of_int);
Результат:
Несколько вещей, которые стоит отметить:
- Я использовал
MemCpy
функцию изMEMUtils
библиотеки. Если у вас его нет или вы не хотите добавлять его в свой проект, вы можете вручную скопировать значения из одного массива в другой с помощьюFOR
цикла. - Я опустил проверку дальности, которая может быть чрезвычайно опасной. Если вам нужна дополнительная защита, добавьте ее сами.
- избегайте передачи
arr_dest
какarr1
илиarr2
. Попытка копирования из массива в себя может привести к проблемам.
Редактировать:
На самом деле, похоже, это работает:
integers: ARRAY [0..1] OF ARRAY [0..2] OF INT := [[2, 4, 6], [1, 3, 5]];
evenNumbers: ARRAY [0..2] OF INT := integers[0];
oddNumbers: ARRAY [0..2] OF INT := integers[1];
Результат:
Но я не знаю, является ли это вашим желаемым результатом. Если вам нужен непрерывный массив в качестве объединенного массива, то вы можете попробовать это:
// in Program
evenNumbers: ARRAY [0..2] OF INT := [2, 4, 6];
oddNumbers: ARRAY [0..2] OF INT := [1, 3, 5];
integers: ARRAY [0..5] OF INT := JOIN_INT_ARRAYS_3_3_6(arr1 := evenNumbers, arr2 := oddNumbers);
// (left)3 (right)3 = (result)6
FUNCTION JOIN_INT_ARRAYS_3_3_6 : ARRAY [0..5] OF INT
VAR_IN_OUT
arr1: ARRAY [0..2] OF INT;
arr2: ARRAY [0..2] OF INT;
END_VAR
VAR
i: USINT;
END_VAR
FOR i := 0 TO 2 DO
JOIN_INT_ARRAYS_3_3_6[i] := arr1[i];
END_FOR
FOR i := 0 TO 2 DO
JOIN_INT_ARRAYS_3_3_6[i 3] := arr2[i];
END_FOR
и результат:
Однако с помощью этого метода функция не может быть общей, поэтому вам придется изменять размеры входных и выходных массивов каждый раз, когда меняются условия, и создавать множество, если вы хотите использовать это в нескольких местах, поэтому это не элегантно, и лично я бы этого избегал, но если это работает для вас, то вот оно.
Кроме того, это, кажется, дает мне C0441: Access to uninitialized VAR_IN_OUT variable
предупреждение, так что еще одна причина попытаться избежать этого.
Комментарии:
1. Хороший способ объединения массивов. Сложный, продвинутый и при этом красивый. Похоже на запутывание кода для большинства разработчиков ПЛК 🙂
2. Мило, но действительно немного сложно. К сожалению, присвоение значений непосредственно в объявлении кажется невозможным.
3. @Роальд, проверь правку 😉