PL/I data types, structures and built-in functions
PL/I describes data by attributes: whether a number is decimal or binary, fixed or floating, and how many digits it has. Strings can be fixed or varying, bits are a real type, and pointers let programs work with storage directly. A large library of built-in functions handles strings, arithmetic and dates.
Arithmetic data
A number in PL/I has a base (DECIMAL or BINARY), a scale (FIXED or FLOAT) and a precision. For business data you use fixed-point types almost exclusively.
| Declaration | Stored as | COBOL equivalent | Typical use |
|---|---|---|---|
| FIXED DECIMAL(7,2) | Packed decimal, 4 bytes | PIC S9(5)V99 COMP-3 | Money, quantities |
| FIXED BINARY(15) | Halfword (2 bytes) | PIC S9(4) COMP | Small counters |
| FIXED BINARY(31) | Fullword (4 bytes) | PIC S9(9) COMP | Counters, subscripts, lengths |
| FLOAT DECIMAL(16) | Floating point | COMP-2 | Scientific values, not money |
In FIXED DECIMAL(7,2) the first number is the total digits and the second the digits after the decimal point, so it holds up to 99999.99. This is the same packed decimal format COBOL uses, which is why the two languages can share files. See FIXED DECIMAL.
Strings and bits
CHARACTER(30)(orCHAR(30)) is always 30 bytes, padded with blanks. Equivalent to COBOLPIC X(30).CHAR(30) VARYINGholds up to 30 characters and stores the current length in a 2-byte prefix. COBOL has no direct equivalent, so mapping it needs care.BIT(1)holds a single bit, written'1'Bor'0'B. Ideal for flags such as end of file.
Structures and arrays
Structures use level numbers like COBOL, but with attributes in PL/I style. Arrays are declared by putting bounds after the name; the lower bound defaults to 1 but can be anything.
DCL 1 CUSTOMER,
2 CUST_ID CHAR(8),
2 CUST_NAME CHAR(30),
2 BALANCE FIXED DEC(11,2),
2 ACTIVE BIT(1);
DCL MONTH_TOTAL(12) FIXED DEC(13,2) INIT((12)0);
DCL RATE_BAND(0:9) FIXED DEC(5,4);
CUSTOMER.BALANCE = CUSTOMER.BALANCE + 100.00;
MONTH_TOTAL(3) = MONTH_TOTAL(3) + BALANCE;INIT((12)0) uses a repeat factor to set all twelve entries to zero. Qualified names such as CUSTOMER.BALANCE use a dot, where COBOL writes BALANCE OF CUSTOMER.
Pointers and BASED storage
A POINTER holds an address. A variable declared BASED(P) has no storage of its own: it is a layout laid over whatever address P holds. This is how PL/I programs walk through buffers, chained lists and control blocks. It is also how they corrupt storage when a pointer is wrong. See BASED storage.
DCL P POINTER;DCL 1 HDR BASED(P), 2 LEN FIXED BIN(31), 2 TYPE CHAR(4);P = ADDR(BUFFER);IF P = NULL() THEN ...Storage classes
AUTOMATIC (the default) is allocated when a block is entered and freed when it ends, so values do not survive between calls. STATIC is allocated once and keeps its value. BASED and CONTROLLED are allocated by the program. Uninitialised AUTOMATIC variables contain whatever was in storage, a classic source of intermittent bugs.
Built-in functions
| Function | Purpose |
|---|---|
| SUBSTR(s, start, len) | Part of a string; can also be assigned to |
| LENGTH(s) | Current length of a string |
| INDEX(s, find) | Position of one string in another, 0 if absent |
| VERIFY(s, chars) | Position of the first character not in a set, 0 if all valid; useful for validating numeric input |
| TRANSLATE(s, to, from) | Replace characters, for example lower case to upper case |
| TRIM(s) | Remove leading and trailing blanks |
| MOD(a, b) / ROUND(x, n) | Remainder; rounding to n decimal places |
| HBOUND / LBOUND / DIM | Array upper bound, lower bound and extent |
| DATETIME() | Current date and time as a character string |
Common mistakes
A VARYING string has a 2-byte length prefix. Sharing it with COBOL as PIC X shifts every field after it. Map it as a halfword length plus text.
AUTOMATIC storage starts with leftover data. Initialise with INIT or an assignment before use.
A null or stale pointer leads to S0C4 or silent corruption. Check the pointer and know who owns the storage.
What you will see at work
- Interface work between PL/I and COBOL programs is mostly about mapping data types correctly, especially VARYING strings and binary precisions.
- PL/I programs that process control blocks or chained buffers use BASED structures heavily; reading them means following the pointers.
- VERIFY and TRANSLATE appear constantly in input-validation code in older PL/I systems.
Key terms
Check your understanding.
Take this lesson's quiz and save your progress. Free.