为什么Codesys可以从非零值开始数组?

huangapple go评论62阅读模式
英文:

Why can Codesys start array from nonzero value?

问题

在某个我参与的 IFM PLC 项目中,我遇到了这段代码:

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

当我在断点处检查这个数组时,我发现它有三个元素:

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

我无法理解为什么有人会这样做,或者为什么这是可能的。我从未见过类似的情况。我没有更多的信息来帮助我理解它的用途(有些部分缺失),但它就是这样声明和使用的。我查阅了文档,也没有找到原因。

为什么会有这种情况,以及在什么情况下你会想要使用这样的数组?

英文:

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?

答案1

得分: 6

CODESYS在他们的文章中提到:

> … 结构化文本基于Pascal编程语言…

而Pascal同样允许任何起始索引,例如:

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

这就是为什么Codesys允许这样做的原因。

然而,存在这样的特性也有原因:

  • 大多数程序员习惯于数组索引从0开始,然而这里有一篇文章列出了从1开始计数索引的编程语言。其中大多数是面向非程序员使用的,比如数学家、工程师等等,而Codesys也不例外(否则为什么会有梯形逻辑存在:P)。

  • 如果开发人员费心允许从0或1开始,那么也可以扩展到用户想要的任何索引。

  • 您可能希望将数组中的索引与实际标识符关联起来。例如,假设您有2台设备和一个表示设备是否运行的2个布尔数组,设备放置在容器#2和#3中,而容器#1没有此类设备。您可以创建2个单独的变量(例如dev2dev3),或者您可以创建一个长度为2的数组,记住索引0表示设备2,索引1表示设备3,或者您可以创建一个大小为4的数组(0、1、2、3)并忽略前2个元素,或者您可以创建一个范围从2到3的数组(:ARRAY [2..3] OF BOOL;)。

这种语言特性只是为了提供更多表达您意图的选项,如果您不喜欢它,您不必使用它(尽管请注意,如果您的函数中接受任何大小的数组,请不要忘记使用LOWER_BOUND函数:D)。

最后,如果您必须使用别人的数组,并且绝对不喜欢其起始索引不是0的想法,因为数组本质上是带有(编译时)元数据的指针,您可以将数组强制转换为指针,并将指针用作数组,这 必须 从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, ']');

上述示例的结果是:

为什么Codesys可以从非零值开始数组?

英文:

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:

为什么Codesys可以从非零值开始数组?

huangapple
  • 本文由 发表于 2023年6月19日 22:04:25
  • 转载请务必保留本文链接:https://go.coder-hub.com/76507403.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定