Overlay in rpgle data structures

22 Views


Here’s a crisp guide to OVERLAY in RPGLE data structures—what it is, why you’d use it, and the gotchas.

What OVERLAY does

OVERLAY makes one field or data structure share the same storage as another field/DS (at the same or a specified byte position). It’s like a C “union” or a byte-map: no copying, just different views of the same bytes.


1) Overlay subfields inside a DS (byte mapping)

**free
dcl-ds Buf  qualified;
  raw    char(20);                    // 20-byte buffer
  id     uns(5)  overlay(raw:1);      // bytes 1-2  (2 bytes)
  qty    int(10) overlay(raw:3);      // bytes 3-6  (4 bytes)
  code   char(3) overlay(raw:7);      // bytes 7-9
  price  packed(7:2) overlay(raw:10); // bytes 10-13 (see packed bytes below)
  flag   char(1) overlay(raw:14);
end-ds;
  • overlay(raw:n) starts at byte n of raw.

  • Great for parsing fixed-format records, sockets, data areas, or API buffers.

Packed storage bytes = ⌊digits/2⌋ + 1 (e.g., 7,2 → 4 bytes).


2) Overlay one DS on another (union-style)

Two DS share the same starting storage. Use this to reinterpret bytes in different ways.

dcl-ds U1  qualified;
  all  char(8);
end-ds;

dcl-ds U2  qualified overlay(U1);   // same 8 bytes as U1
  n    int(10);                     // re-interpret as a 4-byte int (first 4 bytes)
  s    char(4) overlay(n:1);        // look at the int as 4 chars, same bytes
end-ds;

// Now U1.all, U2.n, and U2.s are different views of the same bytes

3) Overlay onto pointer-based DS (dynamic buffers)

Map a variable-length buffer without copying.

dcl-s  p   pointer;

// Assume p points to at least 32 bytes
dcl-ds Msg  based(p) qualified;
  raw    char(32);
  len    uns(5)  overlay(raw:1);
  type   char(2) overlay(raw:3);
  data   char(20) overlay(raw:5);
end-ds;

// Set pointer from receive/read, then use Msg.* subfields directly

4) Overlay within arrays (careful!)

You can overlay array storage, but it’s easy to misalign.

dcl-ds A;
  raw  char(30);
  arr  char(10) dim(3) overlay(raw:1);   // arr(1)=1..10, arr(2)=11..20, arr(3)=21..30
end-ds;

Common patterns

  • Fixed record parsing: Read record into raw then access typed fields via overlays.

  • Union/casting: Share storage across DS to reinterpret bytes (e.g., char↔int).

  • Performance: Avoids %SUBST copies—reads/writes are in-place.


Gotchas & tips

  1. Byte math matters

    • Packed/zoned must start at proper byte boundaries (packed uses nibbles but you specify byte positions; ensure the length exactly fits).

  2. ALIGN can move things

    • ALIGN on a DS repositions subfields to natural boundaries. If you rely on exact byte positions or overlays, avoid ALIGN on that DS (or design with it consistently).

  3. Endianness & representation

    • int/uns are binary; overlays let you see their raw bytes—useful, but representation is platform-specific. Don’t serialize binary ints unless you control both ends.

  4. No copying vs %SUBST

    • OVERLAY is no-copy; %SUBST returns a substring value (copy). For big buffers, overlay is faster.

  5. Debugging

    • Use the debugger’s hex view or DSPPGMVAR (or dump) to confirm byte offsets if something looks off.


Mini cheat sheet

  • Overlay a subfield at byte 1: field overlay(base:1)

  • Overlay whole DS on another: dcl-ds B overlay(A); ... end-ds;

  • Packed bytes: bytes = ⌊digits/2⌋ + 1 (e.g., 5,0 → 3 bytes; 7,2 → 4 bytes)

  • Zoned bytes: bytes = digits

  • Pointer-mapped DS: dcl-ds X based(p); ... end-ds; then p = %addr(buf);


 

Post Comments