Search code examples
codesys

Why can Codesys start array from nonzero value?


In some project I get to work with for an IFM PLC I encountered this code:

someArray:ARRAY  [6..8] OF BYTE;

When I inspect the array on breakpoint I see that it has three elements:

someArray[6] = 0
someArray[7] = 0
someArray[8] = 0

I can't for the life of me understand why anyone would ever do this, or why this is even possible., I have never seen anything like this. I have no further source that could help me understand what it is for (parts are missing), but this is how it is declared and used. I've looked in the documentation and could not find a reason there either.

Why is this possible, and in which situation would you want an array like this?


Solution

  • CODESYS has an article where they say

    ... structured text is based on the Pascal programming language ...

    and Pascal simmilarly allows for any starting index, for example:

    temperature = array [-10 .. 50] of real;
    

    So this is the reason why codesys allows that.

    However, there are also reasons why such feature exists:

    • Most programmers are used to the fact that arrays indices start from 0, however here's an article that lists languages that start counting indices from 1 instead. Most of them are meant to be used by non programmers, such as mathematicians, engineers and etc. and codesys is no exception (why else does ladder logic exist :P).

    • If the developers went to the trouble of allowing starting from 0 or 1, might as well extend it to whatever the user wants.

    • You may want to associate the index in the array to an actual identifier. For example, lets say you have 2 devices and an array of 2 booleans that represent whether the device is running, and the devices are placed in container #2 and #3, with container #1 having no such device. You could create 2 separate variables (eg. dev2, dev3), or you could create an array of 2 and remember that index 0 represents device 2 and index 1 represents device 3, or you could create an array of size 4 (0, 1, 2, 3) and ignore the first 2 elements, or you can create an array of 2 from 2 to 3 (:ARRAY [2..3] OF BOOL;).

    This language feature just gives you more options to express your intent, if you don't like it, you don't have to use it (though do note, if you accept arrays of any size in your functions, don't forget to use the LOWER_BOUND function :D)

    And finally, if you have to use someone else's array and absolutely hate the idea of it's starting index not being 0, since arrays are essentially pointers with (compiletime) metadata, you can just cast the array to a pointer, and use the pointer as an array, which you will have to access from 0:

    arr: ARRAY [7..13] OF INT := [7, 8, 9, 10, 11, 12, 13];
    up_bound: DINT := UPPER_BOUND(arr, 1) - LOWER_BOUND(arr, 1);
    ptr: POINTER TO INT := ADR(arr);
    i: DINT;
    str: STRING;
    
    // ---
    
    str := '[';
    FOR i := 0 TO up_bound - 1 DO
        str := CONCAT(str, INT_TO_STRING(ptr[i]));
        str := CONCAT(str, ', ');
    END_FOR
    str := CONCAT(str, INT_TO_STRING(ptr[i]));
    str := CONCAT(str, ']');
    

    The result of the above example is:

    str | STRING | '[7, 8, 9, 10, 11, 12, 13]'