Как объединить несколько массивов в один массив в codesys

#arrays #merge #codesys

#массивы #слияние #codesys кодовые коды

Вопрос:

У меня есть 4 массива, каждый из которых содержит 10 слов. Цель состоит в том, чтобы объединить эти 4 массива в один больший массив (40 слов) в codesys.

Я могу скопировать содержимое одного массива с помощью указателя следующим образом:

декларация:

 array1: ARRAY [0..9] OF WORD;
array2: ARRAY [0..9] OF WORD;
array3: ARRAY [0..9] OF WORD;
array4: ARRAY [0..9] OF WORD;
masterarray: ARRAY [0..39] OF WORD;
pt: POINTER TO ARRAY [0..39] OF WORD;
 

код:

 pt := ADR(array1);
masterarray := pt^;
 

Я еще не понял, как продолжить отсюда, чтобы объединить остальные массивы. Я привязан к использованию SIZEOF -функции, чтобы определить размер указателя и использовать его в качестве смещения… но поскольку я раньше не пользовался указателями, я не совсем уверен, что мне действительно следует делать.

Комментарии:

1. masterarray := pt^; при этом копируется не только array1 содержимое в начало masterarray , но и все, что находится в памяти после array1 в то время

2. Привет, и спасибо за разъяснения. Я заметил это, и это сработало просто отлично, но только если все 4 массива расположены один за другим в регистрах. Но если я изменил порядок объявления, я все равно получил все значения, перемещенные в новый массив, но в неправильном порядке. Вот почему я ищу решение, в котором перемещение значений выполняется каждый раз, независимо от того, где в регистре они расположены.

Ответ №1:

Ваш первый выбор — выполнять простые циклы:

 i, j: USINT;
len: DINT := UPPER_BOUND(array1, 1); // 9 in your case
 
 FOR i := 0 TO len DO
    masterarray[j] := array1[i];
    j := j   1;
END_FOR
FOR i := 0 TO len DO
    masterarray[j] := array2[i];
    j := j   1;
END_FOR
FOR i := 0 TO len DO
    masterarray[j] := array3[i];
    j := j   1;
END_FOR
FOR i := 0 TO len DO
    masterarray[j] := array4[i];
    j := j   1;
END_FOR
 

Другим вариантом является использование MemoryUtils библиотеки, в частности MemCpy функции:

 MEMUtils.MemCpy(pbySrc := ADR(array1), pbyDest := ADR(masterarray), dwSize := SIZEOF(array1));
i := UPPER_BOUND(array1, 1)   1;
MEMUtils.MemCpy(pbySrc := ADR(array2), pbyDest := ADR(masterarray[i]), dwSize := SIZEOF(array2)); // shift the destination by i (10 in this case)
i := i   UPPER_BOUND(array2, 1)   1;
MEMUtils.MemCpy(pbySrc := ADR(array3), pbyDest := ADR(masterarray[i]), dwSize  := SIZEOF(array3)); // shift the destination by i (20 in this case)
i := i   UPPER_BOUND(array3, 1)   1;
MEMUtils.MemCpy(pbySrc := ADR(array4), pbyDest  := ADR(masterarray[i]), dwSize := SIZEOF(array4)); // shift the destination by i (30 in this case)
 

РЕДАКТИРОВАТЬ: вот небольшая функция, которую я написал:

 // Assume that:
//      - all ARRAYs start at index 0
//      - the destination ARRAY size can fit all source ARRAYs
//      - all ARRAYs store WORDs
FUNCTION MERGE
VAR CONSTANT
    SIZEOF_of_word: USINT := SIZEOF(WORD);
END_VAR
VAR_IN_OUT
    pointers: ARRAY [*] OF POINTER TO WORD;
    sizes: ARRAY [*] OF DWORD;
END_VAR
VAR_INPUT
    destinationPtr: POINTER TO WORD;
END_VAR
VAR
    i: DINT;
    len: DINT := UPPER_BOUND(pointers, 1);
    j: DWORD;
END_VAR

FOR i := 0 TO len DO
    MEMUtils.MemCpy(pbySrc := pointers[i], pbyDest := ADR(destinationPtr[j]), dwSize := sizes[i]);
    j := j   sizes[i] / SIZEOF_of_word;
END_FOR
 
 PROGRAM PLC_PRG
VAR
    array1: ARRAY [0..9] OF WORD := [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
    array2: ARRAY [0..9] OF WORD := [11, 12, 13, 14, 15, 16, 17, 18, 19, 20];
    array3: ARRAY [0..9] OF WORD := [21, 22, 23, 24, 25, 26, 27, 28, 29, 30];
    array4: ARRAY [0..9] OF WORD := [31, 32, 33, 34, 35, 36, 37, 38, 39, 40];
    masterarray: ARRAY [0..39] OF WORD;
    pts: ARRAY[0..3] OF POINTER TO WORD := [ADR(array1), ADR(array2), ADR(array3), ADR(array4)];
    ss: ARRAY[0..3] OF DWORD := [SIZEOF(array1), SIZEOF(array2), SIZEOF(array3), SIZEOF(array4)];
END_VAR

MERGE(pointers := pts, sizes := ss, destinationPtr := ADR(masterarray));
 

PS: я не знаю, является ли это наиболее эффективным способом сделать это

Комментарии:

1. Расскажи мне о ARRAY [*] том, что это такое?

2. Привет, и спасибо за вашу помощь! Этот пример работает безупречно, с небольшим изменением: MEMUtils. MemCpy(pbySrc := ADR(array1), pbyDest := ADR(masterarray), dwSize := SIZEOF(array1)); Изменение касается UPPER_BOUND, поскольку на самом деле у меня нет истинного массива, а несколько структур (с массивами внутри). Эти структуры имеют фиксированную длину, поэтому значение UPPER_BOUND не требуется, и я просто определил i как «смещение», которое было бы таким же, как результат UPPER_BOUND, в случае, если бы у меня был array вместо struct . ADR(masterarray[i] => i = 10, 20 и 30

3. @MrHUU, true, если у вас массивы фиксированной длины. Я просто обобщил для дальнейшего использования 😉

4. @SergeyRomanov, массивы переменной длины . В принципе, есть 3 способа передать массив в func / fb: 1. Предопределенная фиксированная длина (не гибкая). 2. Передайте указатель и длину массива (гибкий, но некоторым не нравятся указатели) 3. Передайте массив в VAR_IN_OUT как массив переменной длины (в принципе, он может быть любого размера, и для получения границ [x..y] вы используете LOWER_BOUND(arr, 1) для x и UPPER_BOUND(arr, 1) для y). На самом деле, это похоже на вариант 2, но вам не нужно передавать длину

5. @Guiorgy это работает только для VAR_IN_OUT области видимости?