数据结构示例
以下示例显示了数据结构的各种用途以及如何定义这些结构。
| 示例 | 描述 |
|---|---|
| 使用数据结构对字段进行细分 | 使用数据结构对字段进行细分 |
| 使用数据结构对输入记录中的字段进行分组 | 使用数据结构对字段进行分组 |
| 使用具有数据结构的关键字 QUALIFIED , LIKEDS 和 DIM | 将关键字 QUALIFIED , LIKEDS 和 DIM 与数据结构配合使用,以及如何对标准子字段进行编码 |
| 具有绝对和长度表示法的数据结构 | 具有绝对和长度表示法的数据结构 |
| 重命名并初始化外部描述的数据结构 | 重命名和初始化外部描述的数据结构 |
| 使用 PREFIX 重命名外部数据结构中的所有字段 | 使用 PREFIX 重命名外部数据结构中的所有字段 |
| 定义多实例数据结构 | 定义多实例数据结构 |
| 对齐数据结构子字段 | 对齐数据结构子字段 |
| 定义 *LDA 数据区数据结构 | 定义 *LDA 数据区数据结构 |
| 使用数据区数据结构在程序之间进行通信 | 使用数据区数据结构在程序之间进行通信 |
| 使用指示符数据结构 | 使用指示符数据结构 |
| 使用多实例指示符数据结构 | 使用多次出现的指示符数据结构 |
| 定义常量数据结构 | 定义常量数据结构 |
使用数据结构对字段进行细分
文件 FILEIN 中的记录包含需要在此程序中进行处理的字段 Partno。 为此,使用以下数据结构定义将字段 Partno 描述为数据结构。
DCL-DS Partno;
Manufactr CHAR(4);
Drug CHAR(6);
Strength CHAR(3);
Count ZONED(3);
END-DS;
您可以使用 Partno或使用各个子字段 Manufactr, Drug, Strength 或 Count来引用整个数据结构。
以下示例显示了以固定格式定义的相同数据结构。 使用长度表示法来定义数据结构子字段。
D Partno DS
D Manufactr 4
D Drug 6
D Strength 3
D Count 3 0
D使用数据结构对输入记录中的字段进行分组
来自 TRANSACTN 的输入记录按此顺序具有以下字段:
- PARTNO
- QUANTITY
- TYPE
- CODE
- LOCATION
另一个文件 ITEMMASTER 具有单个字段 ITEM_NBR ,其中包含 LOCATION, PARTNO和 TYPE 数据。
您可以使用数据结构对 TRANSACTN 文件中的 3 字段进行分组,以便它们与 ITEMMASTER 文件中的 ITEM_NBR 字段匹配。
使用数据结构对字段进行分组时,可以使输入记录上非相邻位置的字段占据相邻的内部位置。 然后,可以通过数据结构名或单个子字段名称来引用该区域。
以下数据结构将 Location, Partno和 Type 分组到数据结构 Partkey中。 不需要为子字段指定类型信息,因为类型信息来自文件中的字段。
DCL-DS Partkey;
Location;
Partno;
Type;
END-DS;
从文件中读取记录时,记录中的 LOCATION, PARTNO和 TYPE 字段中的数据将移至 Partkey 数据结构的 Location, Partno和 Type子字段。 然后,可以将 Partkey 数据结构与 ITEMMASTER 文件中的 Item_Nbr 字段进行比较。
READ ITEMMASTER;
. . .
READ TRANSACTN;
IF Partkey = Item_Nbr;
. . .
ENDIF;
将关键字 QUALIFIED , LIKEDS 和 DIM 与数据结构配合使用
以下定义定义了两个模板数据结构 CustomerInfo 和 ProductInfo。 模板数据结构用于定义 B数据结构数组的数据结构子字段 SalesTransaction。
D CustomerInfo DS QUALIFIED TEMPLATE
D Name 20A
D Address 50A
D ProductInfo DS QUALIFIED TEMPLATE
D Number 5A
D Description 20A
D Cost 9P 2
D SalesTransaction...
D DS QUALIFIED
D Buyer LIKEDS(CustomerInfo)
D Seller LIKEDS(CustomerInfo)
D NumProducts 10I 0
D Products LIKEDS(ProductInfo)
D DIM(10)
TotalCost = 0;
for i = 1 to SalesTransation. Numproducts;
TotalCost = TotalCost + SalesTransaction.Products(i).Cost;
dsply SalesTransaction.Products(i).Cost;
endfor;
dsply ('Total cost is ' + %char(TotalCost));
具有绝对和长度表示法的数据结构
定义名为 FRED的程序描述数据结构。 数据结构由 5 字段组成:
- 具有元素长度 10 和维度 70 的数组 Field1 。
- 长度为 30 的字段 Field2 。
- 占用与 Field2第一部分相同的存储器的字段 Field3 。
- 字段 Field4 占用与 Field2的最后部分相同的存储器。
- 二进制字段 Field5 占用与 Field3的前 2 个字节相同的存储器。
使用具有绝对表示法的固定格式定义来定义每个字段的起始位置和结束位置。 编译器通过将总长度 700 除以维 70 来确定 Field1 数组的每个元素的长度。
D FRED DS
D Field1 1 700 DIM(70)
D Field2 701 730
D Field3 701 715
D Field5 701 704B 2
D Field4 716 730
将自由格式定义与 OVERLAY 关键字配合使用以细分字段。
DCL-DS FRED;
Field1 CHAR(10) DIM(70);
Field2 CHAR(30);
Field3 CHAR(15) OVERLAY(Field2);
Field5 BINDEC(4:2) OVERLAY(Field3);
Field4 CHAR(15) OVERLAY(Field2:16);
END-DS;
将固定格式定义与 OVERLAY 关键字配合使用以细分字段。
D FRED DS
D Field1 10 DIM(70)
D Field2 30
D Field3 15 OVERLAY(Field2)
D Field5 4B 2 OVERLAY(Field3)
D Field4 15 OVERLAY(Field2:16)
重命名和初始化外部描述的数据结构
- 使用内部名称 FRED 和外部名称 EXTDS定义外部描述的数据结构。
- 将字段 CUST 重命名为 CUSTNAME。
- 将 CUSTNAME 初始化为 "GEORGE" ,并将 PRICE 初始化为 1234.89。
- 指定子字段 ITMARR的 DIM 关键字。 ITMARR 子字段在外部描述中定义为 100 字节字符字段。 这将 100 字节字符字段划分为 10 个数组元素,每个数组元素的长度为 10 个字节。警告: 在外部描述的数字子字段上使用 DIM 关键字时应谨慎,因为它会将该字段划分为数组元素,这些元素可能没有数组的每个元素的有效数字数据。
使用自由格式定义:
DCL-DS Fred EXTNAME('EXTDS');
CUSTNAME EXTFLD('CUST') INZ('GEORGE');
PRICE EXTFLD INZ(1234.89);
ITMARR EXTFLD DIM(10);
END-DS;
使用固定格式定义:
D Fred E DS EXTNAME(EXTDS)
D CUSTNAME E EXTFLD(CUST) INZ('GEORGE')
D PRICE E INZ(1234.89)
D ITMARR E DIM(10)
使用 PREFIX 重命名外部数据结构中的所有字段
在以下数据结构定义中,外部子字段名称以 "CU_" 作为前缀,除非已使用 EXTFLD 关键字重命名该子字段。
- 数据结构的自由格式定义
- EXTFLD 用于标识外部子字段。 通过将新名称指定为关键字的参数,可以使用 EXTFLD 关键字来重命名子字段。 在以下示例中,外部字段 NUMBER 重命名为 Custnum。
DCL-DS extds1 EXTNAME('CUSTDATA') PREFIX(CU_); Name EXTFLD INZ('Joe''s Garage'); Custnum EXTFLD('NUMBER'); END-DS; - 同一数据结构的固定定义
- 在第 22 列中指定 "E" 以将子字段标识为外部子字段。 使用 EXTFLD 关键字为子字段指定新名称。
... 1 ...+... 2 ...+... 3 ...+... 4 ...+... 5 ...+... 6 DName+++++++++++ETDsFrom+++To/L+++IDc.Keywords++++++++++++ D extds1 E DS EXTNAME (CUSTDATA) D PREFIX (CU_) D Name E INZ ('Joe''s Garage') D Custnum E EXTFLD (NUMBER)
先前的数据结构由编译器展开如下:
- 所有外部描述的字段都包含在数据结构中。
- 将为使用 EXTFLD 关键字的参数重命名的子字段分配其新名称。
- 未重命名的子字段以前缀字符串作为前缀。
扩展的数据结构:
D EXTDS1 E DS
D CU_NAME E 20A EXTFLD (NAME)
D INZ ('Joe's Garage')
D CU_ADDR E 50A EXTFLD (ADDR)
D CUSTNUM E 9S 0 EXTFLD (NUMBER)
D CU_SALESMN E 7P 0 EXTFLD (SALESMN)定义多实例数据结构
使用以下内容定义包含 20 个元素的多实例数据结构:
- 类型为字符和长度为 20 的 3 字段
- 类型为字符的字段,长度为 10 ,与从位置 2 开始的第二个字段重叠。
- 使用使用开始位置和结束位置的绝对表示法定义子字段
命名常量 Max_Occur 用于定义出现次数。
D Max_Occur C CONST(20) D DDataStruct DS OCCURS (Max_Occur) D field1 1 20 D field2 21 40 D field21 22 31 D field3 41 60- 使用绝对表示法和长度表示法混合定义子字段
D DataStruct DS OCCURS(20) D field1 20 D field2 20 D field21 22 31 D field3 41 60
对齐数据结构子字段
有关对齐的信息,请参阅 ALIGN{(*FULL)} 。
在以下示例中
- 使用 ALIGN定义的数据结构。 仅使用长度表示法定义的子字段由编译器对齐。 使用起始位置定义的子字段将由编译器进行检查以进行对齐,如果该子字段未对齐,那么将发出警告消息。
- 整数子字段是使用绝对表示法定义的。 子字段位于 4 字节边界上,因此它们正确对齐。
- 整数子字段是使用长度表示法定义的。 Subf3 位于位置 41-42 中,直接位于 Subf2之后,因为位置 41 位于 2 字节边界上。 但是, Subf4 必须放在位置 45-48 中,这是位置 42 之后的下一个 4 字节边界。
- 整数子字段是使用 OVERLAY定义的。 子字段 Group 在 4 字节边界上定义,这是正确的,因为其需要对齐的最大覆盖子字段 Subf7是 4 字节整数。 由于在 OVERLAY 关键字中指定了有效的起始位置,因此重叠的子字段 Subf6, Subf7和 Subf8 正确对齐。
- 使用绝对表示法定义的整数子字段未正确对齐。 SubfX1 的起始位置为 10 ,这不是 2 字节对齐。 SubfX2 的起始位置为 15 ,这不是 4 字节对齐的。
- 使用 OVERLAY 定义的整数子字段未正确对齐。 子字段 BadGroup 在 4 字节边界上定义。 但是, OVERLAY 关键字指定的子字段的起始位置会导致子字段未正确对齐。
- 由于覆盖结构 WorseGroup 未在 4 字节边界上对齐,因此使用 OVERLAY 定义的整数子字段未正确对齐。
D MyDS DS ALIGN 1
D Subf1 33 34I 0 2
D Subf2 37 40I 0 2
D Subf3 5I 0 3
D Subf4 10I 0 3
D Group 101 120A 4
D Subf6 5I 0 OVERLAY (Group: 3) 4
D Subf7 10I 0 OVERLAY (Group: 5) 4
D Subf8 5U 0 OVERLAY (Group: 9) 4
D SubfX1 10 11I 0 4
D SubfX2 15 18I 0 4
D BadGroup 101 120A 6
D SubfX3 5I 0 OVERLAY (BadGroup: 2) 6
D SubfX4 10I 0 OVERLAY (BadGroup: 6) 6
D SubfX5 10U 0 OVERLAY (BadGroup: 11) 6
D WorseGroup 200 299A 7
D SubfX6 5I 0 OVERLAY (WorseGroup) 7
D SubfX7 10I 0 OVERLAY (WorseGroup: 3) 7
由于以下原因,子字段接收警告消息:
- SubfX1: 对于 2 字节字段,结束位置 11 不是 2 的倍数。
- SubfX2: 结束位置 18 不是 4 字节字段的 4 的倍数。
- SubfX3: 结束位置 103 不是 2 的倍数。
- SubfX4: 结束位置 109 不是 4 的倍数。
- SubfX5: 结束位置 114 不是 4 的倍数。
- SubfX6: 结束位置 201 不是 2 的倍数。
- SubfX7: 结束位置 205 不是 4 的倍数。
定义 *LDA 数据区数据结构
基于 *LDA 定义数据区数据结构。
- 没有名称的数据区数据结构基于 *LDA。
- 为 DTAARA 关键字指定了 *AUTO 的自由格式定义:
DCL-DS *N DTAARA(*AUTO); SUBFLD CHAR(600); END-DS;具有定义类型 U的等效固定格式定义。 在这种情况下,不必使用 DTAARA 关键字。D UDS D SUBFLD 1 600A - 数据结构显式基于 *LDA。 由于它不是数据区数据结构,因此必须使用 IN 和 OUT 操作进行处理。
- 自由格式定义:
DCL-DS LDA_DS DTAARA(*LDA); SUBFLD CHAR(600); END-DS; IN LDA_DS; OUT LDA_DS;数据结构的等效固定格式定义:D LDA_DS DS DTAARA(*LDA) D SUBFLD 1 600A - 数据结构显式基于 *LDA。 它是一个数据区数据结构,因此它在初始化期间被读入,在终止期间被写出。 还可以使用 IN 和 OUT 操作来处理此问题。
- 自由格式定义。 *AUTO 参数将其定义为数据区数据结构。 *USRCTL 参数指定可以使用 IN 和 OUT 操作对其进行处理。
- 在程序初始化期间将数据区读入数据结构后,在程序开始时显示数据结构的值。
- 更改数据结构的值。
- 写出数据区
DCL-DS LDA_DS DTAARA(*LDA : *AUTO : *USRCTL); SUBFLD CHAR(50); END-DS; DSPLY SUBFLD; 1 SUBFLD = 'New value'; 2 OUT LDA_DS; 3数据结构的等效固定格式定义。 U 定义类型将其定义为数据区数据结构。 DTAARA 关键字指定可以使用 IN 和 OUT 操作进行处理。D LDA_DS UDS DTAARA(*LDA) D SUBFLD 1 50A
使用数据区数据结构在程序之间进行通信
程序 1: 此程序使用数据区数据结构来保存一系列总计的累积值。
- 在程序初始化期间将数据区读入数据结构。
- 然后,将数据区子字段添加到文件 SALESDTA 中的字段。
- 设置了指示符 *INLR ,以便在程序结束时写出数据区。
DCL-F SALESDTA;
DCL-DS Totals DTAARA(*AUTO); // 1
Tot_amount ZONED(8:2);
Tot_gross ZONED(10:2);
Tot_net Zoned(10:2);
END-DS;
. . .
Tot_amount = Tot_amount + amount; // 2
Tot_gross = Tot_gross + gross;
Tot_net = Tot_net + net;
. . .
*INLR = *ON; // 3
程序 2: 此程序处理在程序 1 中计算的总计。
- 在程序初始化期间将数据区读入数据结构。
- 在计算中使用数据区子字段。
DCL-DS Totals DTAARA(*AUTO); // 1
Tot_amount ZONED(8:2);
Tot_gross ZONED(10:2);
Tot_net Zoned(10:2);
END-DS;
. . .
*IN91 = (Amount2 <> Tot_amount);// 2
*IN92 = (Gross2 <> Tot_gross);
*IN93 = (Net2 <> Tot_net);
. . .
使用指示符数据结构
- INDDS 关键字将 DispInds 数据结构标识为文件 Disp的指示符数据结构。
- 已定义指示符数据结构 DispInds 。 每个子字段的位置与用于控制显示文件的指示符号相同。 例如,如果显示文件引用了指示符 21 ,请指定 21 作为该指示符在数据结构中的位置。
- 设置指示符以控制子文件。
- 指示符数据结构中的指示符用于控制 EXFMT 操作。
- 使用指示符数据结构允许将可读名称用于 EXFMT 操作设置的指示符。
DCL-F Disp WORKSTN INDDS(DispInds); // 1
DCL-DS DispInds; // 2
// Format QUERY
ShowName IND POS(21);
Exit IND POS(3);
Cancel IND POS(12);
BlankNum IND POS(31);
// Format DISPSFLCTL
SFLDSP IND POS(42);
SFLEND IND POS(43);
SFLCLR IND POS(44);
END-DS;
. . .
SFLDSP = *ON; // 3
SFLEND = *OFF;
SFLCLR = *OFF;
EXFMT DispSFLCTL; // 4
EXFMT Query;
IF Exit or Return; // 5
*INLR = *ON;
RETURN;
ENDIF;
使用多次出现的指示符数据结构
当您使用多实例数据结构作为文件的指示符数据结构时,可以对文件中的每个记录格式使用不同的实例。
- QUERY 格式提示用户输入名称。 格式有 3 个响应指示符, 03,05 和 12。
- ERRMSG 格式显示错误消息。 该格式具有 3 条件指示符, 01 , 02 和 03 ,用于控制显示的错误消息。
指示符 03 用于这两种格式。
- INDDS 关键字将 DispInds 数据结构标识为文件 Disp的指示符数据结构。
- 指示符数据结构 DispInds 定义为多实例数据结构,文件中的每个记录格式都有一个实例。 出现次数由命名常量 NUM_FORMATS设置。
- 这两种格式都将指示符 03 用于不同的用途。
- 为 CheckName 过程可能返回的值定义了常量。 可以使用常量
- 当显示可能设置响应指示符 03,05 和 12 的 QUERY 格式时,将使用第一次出现的数据结构。
- 当显示可能已设置条件指示符 01 , 02 或 03 的 ERRMSG 格式时,将使用数据结构的第二次出现。
A INDARA
A R QUERY CA03(03) CA05(05) CA12(12) 1
A 3 2'Enter the name'
A NAME 20A B 3 30CHECK(LC)
A 23 2'03=Exit 05=Refresh 12=Return'
A COLOR(BLU)
A R ERRMSG 2
A NAME 20A O 4 2
A 01 4 30'Not found'
A 02 4 30'Not valid'
A 02 4 30'Not valid'
A 03 5 3'Not unique'
DCL-F Disp WORKSTN INDDS(DispInds); // 3
DCL-C NUM_FORMATS 2; // 4
DCL-DS DispInds OCCURS(NUM_FORMATS) INZ; // 4
// Format QUERY
Exit IND POS(3); // 5
Refresh IND POS(5);
Cancel IND POS(12);
// Format ERRMSG
NotFound IND POS(1);
NotValid IND POS(2);
NotUnique IND POS(3); // 5
END-DS;
DCL-C NameOk 0; // 6
DCL-C NameNotFound 1;
DCL-C NameNotValid 2;
DCL-C NameNotUnique 3;
DCL-S rc INT(10);
DOU Exit or Cancel;
%OCCUR(DispInds) = 1; // 7
EXFMT QUERY;
SELECT; // 7
WHEN Exit or Cancel;
*INLR = *ON;
RETURN;
WHEN Refresh;
RESET QUERY;
ITER;
ENDSL;
rc = CheckName (name);
IF rc <> NameOk;
%OCCUR(DispInds) = 2; // 8
CLEAR DispInds;
SELECT rc;
WHEN-IS NameNotFound;
NotFound = *ON;
WHEN-IS NameNotValid;
NotValid = *ON;
WHEN-IS NameNotUnique;
NotUnique = *ON;
ENDSL;
EXFMT ERRMSG;
ENDIF;
ENDDO;
定义常量数据结构
- 数据结构 info_defaults 是使用 CONST定义的。 编译器不允许更改数据结构的子字段。
- 数据结构 info 定义为具有与 info_defaults相同的子字段和初始化值。
- 如果子字段 info.branch 与 branch 子字段的缺省值不同,那么将调用过程 changeBranch 。
- 将为数据结构 info 的子字段分配其缺省值。
DCL-DS info_defaults CONST QUALIFIED; // 1
branch VARCHAR(20) INZ('Main branch');
address VARCHAR(40) INZ('123 Elm St');
END-DS;
DCL-DS info LIKEDS(info_defaults) INZ(*LIKEDS); // 2
. . .
getBranchInfo (info);
if info.branch <> info_defaults.branch; // 3
changeBranch (info);
endif;
. . .
EVAL-CORR info = info_defaults; // 4