arraysvariable-assignmentassigncodesys

CODESYS: Can I assign and array to another array?


Can I perform the following operation in codesys?

VAR

    abVariable_A:    ARRAY[0..15] OF BYTE := [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16];

    abVariable_B:    ARRAY[1..16] OF BYTE := [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0];

END_VAR

abVariable_B := abVariable_A;

What would the result of abVariable_B be? Can I expect it to be equal to

[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16]

Or I will get

[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15]

Please pay attention to the dimension of the arrays, although both have a dimension of 16, the indexes don't start at the same point. Does this affect the assignation of the arrays?

I expect abVariable_B to be equal to [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16].


Solution

  • We can do a simple experiment by running:

    PROGRAM Test
    VAR
        abVariable_A: ARRAY[0..15] OF BYTE := [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16];
        abVariable_B: ARRAY[1..16] OF BYTE := [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0];
        
        pA_before: POINTER TO BYTE;
        pB_before: POINTER TO BYTE;
        pA_after: POINTER TO BYTE;
        pB_after: POINTER TO BYTE;
    END_VAR
    
    pA_before := ADR(abVariable_A);
    pB_before := ADR(abVariable_B);
    
    abVariable_B := abVariable_A;
    
    pA_after := ADR(abVariable_A);
    pB_after := ADR(abVariable_B);
    END_PROGRAM
    

    And observing the result:

    Results

    As we can see, the values in both arrays are the same, and array addresses didn't change (that means all values were copied, instead of just the array reference/pointer like in many other languages).

    We can double check that the values were copied and that the arrays don't point to the same array by modifying one of the values in one array:

    abVariable_B := abVariable_A;
    abVariable_B[3] := 255;
    

    And observing the result:

    Results2

    This experiment shows that codesys treats array assignment as a memory copy for all values (at least in CODESYS 3.5.16, haven't tested this on older versions).

    The initial index has absolutely no importance to the underlying memory layout of an array, it is just there for programmers convenience. However, the same can't be said about arrays of different length:

    abVariable_A: ARRAY[0..15] OF BYTE := [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16];
    abVariable_B: ARRAY[1..18] OF BYTE := [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0];
    

    Results in the C0032: Cannot convert type 'ARRAY [0..15] OF BYTE' to type 'ARRAY [1..18] OF BYTE' error when we try to assign abVariable_A to abVariable_B.

    Simmilar error is shown if abVariable_A is larger than abVariable_B.

    If don't trust the built-in array assignment, or want to handle the above cases, where the arrays have different lengths, you could create a custom function, for example:

    FUNCTION ArrayCopy
    VAR_INPUT
        destination: ANY;
        source: ANY;
    END_VAR
    
    MEMUtils.MemCpy(pbyDest := destination.pValue, pbySrc := source.pValue, MIN(destination.diSize, source.diSize));
    
    END_FUNCTION
    

    If we use it instead of the assignment:

    ArrayCopy(abVariable_B, abVariable_A);
    abVariable_B[3] := 255;
    

    The result is as expected:

    Results3

    Though, keep in mind, the function above requires the MemoryUtils library, and is just an example. Although it works with arrays of any type, it has drawbacks: