1

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?

Malinko
  • 124
  • 11
  • Are you asking about a language feature, state of mind of a programmer who wrote the program you're working on, or just ranting? : ) – Agent_L Jun 19 '23 at 14:30
  • 1
    If you are used to languages where the first element is at index 0, you design around this limitation, and internalize it until you do not even realize the things you do to work around this limitation. This limitation has both pros and cons (reduces expressiveness, but also makes everyone used to the same way to do things). The initial reason for having forced zero-based arrays is likely lost to history, but could very well be very that it avoid an integer operation, probably nothing really fundamental. Then it becomes a culture and "the only way to do things" to those used to it. – Fred Jun 19 '23 at 14:39
  • 1
    For the record, almost all my arrays are zero-based. I think I have a case or two where I have not gone that route because it yielded a cleaner design in a way I thought was worth deviating from my habit. – Fred Jun 19 '23 at 14:41
  • 1
    @Fred why arrays are zero based is simple, an array is just a continuous block of memory, and an element at index *i* is just the memory at offset *i*, and offset 0 *IS* the first element of the array. Also, if you use an unsigned integer as the index (like a BYTE for example), if you skip index 0 then you reduce the total index space, and the max array size, by 1. Those limitations might sound laughable today, but programming begun in the era where even 1 bit was super expensive, can't be wasting any! – Guiorgy Jun 19 '23 at 14:56
  • @ Agent_L As stated I wanted to know why it was possible (it might be something very handy I didn't know, I'm new to Codesys) and a good dose of curiosity and childlike sense of wonder I guess.. – Malinko Jun 19 '23 at 18:30
  • 1
    @Guiorgy in all programming languages, even those who force zero-based indexes, the compiler/interpreter performs address arithmetic for arrays, because although the first item might be at offset 0, the next item is likely not at offset 1 because the size of items varies. It is a case of calculating "base_address + index * size" vs. "base_address + ( index - first_index ) * size. Programming languages supporting arbitrary indexes surely do not waste space, they will just perform that additional addition. – Fred Jun 20 '23 at 15:40
  • 1
    This is why, to me, this feels like a false argument. We all implicitly accept the compiler performs arithmetic operations on indexes. It has to. Deciding whether to force arrays to start at 0 or not is a design decision that comes with a tradeoff. There is no right way to do it, each method has its pros and cons, you might prefer one way or the other and be bothered by the other way to do it, but it is a matter of habit. – Fred Jun 20 '23 at 15:44
  • 1
    @Fred firstly, by offset I meant accounting for the size of the data. And while yes, compilers can absolutely obfuscate this, but as I said, if you have something more primitive or even assembly, then you may not have arrays at all and be working with pointers dirrectly. It's also useful if arrays and pointers act simmilarly (arr[i] and ptr + (i * dsize) point to the same element). As for wasting space, in codesys strings are indexed from 0 and their max size is 255. Assuming string index (i in [i]) is a BYTE, and you started from 1, max size would be 255-1=254, so you waste 1 character. – Guiorgy Jun 20 '23 at 17:03

1 Answers1

6

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

Guiorgy
  • 1,405
  • 9
  • 26
  • 2
    Good answer! I wouldn't rant the language as it's quite common practice to start arrays from 0 even in PLC world. I would rant the programmer who has done that choice without leaving a comment describing the reason. There might be one, or not. – Quirzo Jun 19 '23 at 18:11