Users

Addressing arrays

qianmoQqianmoQ· 更新于 2026-09-30· 阅读 18 分钟· 0 次阅读

登录后可跨设备保存划线和私人笔记登录

Every PLC4X driver selects array elements the same way, in PLC4J and in PLC4Go alike. The address itself differs per protocol - an S7 data block, a Modbus register, an OPC UA node - but what comes after it does not:

<driver-specific address>[<selection>]:<TYPE>

The selection sits before the type. Where a driver’s address carries no type, it ends the address.

The same address means the same thing in either language: one address, written once, used from Java or Go.

The forms

WrittenMeansExample
(omitted)the whole value - a scalar, or every element of an arraymyTag
[n]one element, the one at index nmyTag[4] - the fifth element
[lo..hi]an array of the elements lo through hi, both includedmyTag[0..7] - eight elements
[n;base]one element, in an array the PLC declares as starting at basemyTag[1;1] - the first element
[lo..hi;base]a range, in an array declared as starting at basemyTag[4..7;1] - four elements, starting at the fourth
[…][…]one bracket per dimensionmyTag[1..2][0..5]

A single index is not an array

myTag[4] selects one element and gives you a scalar. myTag[4..4] selects a range that happens to hold one element and gives you a list of one. The difference is deliberate: it is how a tool reading getArrayInfo() decides whether to render a value or a list.

Arrays that do not start at zero

IEC 61131 lets an array be declared ARRAY[1..10] OF BYTE, and the indices the PLC program shows you then start at 1. Write those indices, and add ;base so the driver knows where the data really begins:

%DB42:28.0[4..7;1]:BYTE

That reads four bytes, starting three elements past the address - because element 4 of an array declared from 1 is the fourth.

Some drivers already know the declared bounds from the device: ADS, UMAS and OPC-UA learn them from the symbol table or the address space. There you can simply write the declared indices, and ;base becomes a statement of intent the driver checks against what the device says. A base that disagrees is reported, because it means the address was written against a different layout than the PLC has.

Multi-dimensional arrays

Two spellings are accepted and mean the same thing - the second is what Allen-Bradley and others use:

g_matI16_2x3[1..2][3..4]
g_matI16_2x3[1..2,3..4]

getAddressString() always produces the first, so an address you read back from a tag is in one canonical spelling regardless of how it was written.

A range may only be the last dimension. a[1].b[2..5] is fine - one path to one structure, then a run of its elements. a[1..3].b is not: member b of three separate elements is not one contiguous read, and no protocol here fetches that in a single request. The same goes for a[1..3][2], a strided slice.

What each driver can express

The notation is the same everywhere; what a protocol can carry is not.

DriverDimensionsWhole arrayNotes
OPC-UAmanyyesOmitting the selection asks for the whole node
ADSmanyyesDeclared bounds come from the symbol table
UMASmanyyesSelecting elements is not implemented yet and is reported
EtherNet/IP1noA CIP index is a uint 8, so it cannot start past 255
S7, Modbus, SLMP1noMemory offsets; the base is resolved into the address
Simulated, Profinet1noCan only select from the first element
Firmata1noNo type suffix, so the selection ends the address
KNXnet/IP1noDevice addresses only; a property selection moves the start index

Where a protocol cannot express what you wrote, the driver says so. It will not quietly read something else.

The two bindings do not carry the same set of drivers, and a driver present in both is not always at the same depth. Where a driver in both accepts a selection, the notation and its meaning are identical; what differs is which drivers accept one at all:

  • PLC4Go has no Profinet driver.
  • PLC4Go’s OPC-UA driver takes no selection - its addresses are a NodeId and a type. PLC4J’s, which is where this notation came from, takes the full grammar.
  • PLC4Go’s UMAS driver accepts a bare index inside a symbolic path (myVar[1].member[2]) but not a range; PLC4J’s parses ranges and reports selecting elements as unsupported.
  • PLC4Go’s KNXnet/IP driver has the device address forms in the table above. PLC4J’s has no equivalent.

Brackets that are not array selections

Three address forms use square brackets for something else entirely. They are unchanged by this notation, and the notation’s own spellings are not accepted there:

  • C-Bus writes the arguments of a CAL command in brackets - recall=[param, count]. The count is an argument of the command, not a selection appended to an address.
  • KNXnet/IP group addresses write a set of group addresses to match - 1/[2-3]/4, and [1,3]/2/[4-6]. That is a filter over addresses, not a selection within one value.
  • BACnet/IP writes a property’s array index - ANALOG_VALUE,2/PRESENT_VALUE[3]. This is an index, and already means what an index means here, so nothing about it changed.

Why ; and not something else

The ; before a declared base is the one separator the notation adds. It is kept as ; for three reasons:

  • OPC UA addresses already use ; as the separator of the standard NodeId string form (ns=2;i=MyInt, from OPC UA Part 6). That is not PLC4X’s to redefine - people copy those strings out of their tooling - so ; was already part of the vocabulary.
  • It stays visually distinct from :, which separates the type. %DB42:28.0[4..7;1]:BYTE is readable; the same address with four colons doing three different jobs is not.
  • : is structural in S7, Modbus, SLMP, EtherNet/IP and ADS addresses, whereas ; is structural in only one driver. Reusing the less overloaded character inside brackets keeps the grammar unambiguous.

Upgrading

The brackets used to come after the type on several drivers, where they meant a count:

holding-register:1:INT[4]      (1)
holding-register:1[0..3]:INT   (2)
1before - four registers
2now

An address in the old form no longer parses, and the error tells you what to write instead. That is deliberate: [4] used to mean "four elements" and now means "the fifth", so an address that still parsed would quietly return different data.

Firmata is the exception. Its addresses carry no type (3[4]), so its brackets did not move and there is nothing to reject. 3[4] used to mean four pins from pin 3 and now means one pin, the fifth. Rewrite these as 3[0..3].
PLC4Go’s ADS driver is a second exception. Its [n] used to be a count of n elements, unlike PLC4J’s, so MAIN.g_arr[3] read three elements and now reads one - the element at index 3. Rewrite these as MAIN.g_arr[0..2]. Its [a:b] start-and-count form, which PLC4J never had, is gone: write [a..a+b-1]. These two changes are also what makes the same ADS address mean the same thing in both languages, which it did not before.

A count of zero no longer has a spelling anywhere. Several drivers used to accept [0] and reject it as "quantity must be greater than zero"; a range is written with the indices it covers, so there is no way to ask for no elements at all, and [0] now selects the first one.

评论

登录后参与评论

正在加载评论…