如何在 TwinCAT 中将初始化数组分配给数组数组

How to assign an initialized array to an array of arrays in TwinCAT

我正在尝试将两个初始化数组 evenNumbersoddNumbers 分配给数组 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

这段代码给我一个编译器错误

Array initialisation expected

当然我可以直接用我想要的数字初始化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

但是,如果原始数组非常大 and/or 我想记录这些不同的数组是什么,最好有一个描述性的名称。 IE。 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]];,但这给了我编译器错误:

Cannot convert type 'ARRAY [1..3] OF INT' to type 'INT'

现在我想知道这是否可能?如果是这样,有人知道我该怎么做吗?

要分配多级数组,您可以在一行中完成。

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];

因为evenNumbersoddNumbers在使用的时候都没有初始化。如果您在 VAR CONSTANT 中声明它们,它可能会起作用,但您将无法在程序中更改这些数组的内容。

我不认为你可以在初始化第三个时加入数组(见下面的编辑)。但是,您可以做的是在程序开始时调用一个函数,将这两个数组连接起来:

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);

结果:

注意几点:

  • 我使用了 MEMUtils 库中的 MemCpy 函数。如果您没有它,或者不想将它添加到您的项目中,您可以使用 FOR 循环手动将值从一个数组复制到另一个数组。
  • 我省略了范围检查,这可能非常危险。如果你想要额外的保护,那就自己添加吧。
  • 避免将 arr_dest 作为 arr1arr2 传递。尝试从数组复制到自身可能会导致问题。

编辑:

实际上,这似乎有效:

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 警告,所以另一个尽量避免它的理由。