COBOL 将 0 添加到 COMPUTE 中的变量
Posted
技术标签:
【中文标题】COBOL 将 0 添加到 COMPUTE 中的变量【英文标题】:COBOL add 0 to a Variable in COMPUTE 【发布时间】:2011-12-14 21:36:29 【问题描述】:我在 $WORK 中处理 COBOL 程序时遇到了一个奇怪的语句。
我们有一个段落正在打开一个游标(来自 DB2),并且在它上循环直到它碰到一个 EOT(在伪代码中):
... working storage ...
01 I PIC S9(9) COMP VALUE ZEROS.
01 WS-SUB PIC S9(4) COMP VALUE 0.
... code area ...
PARA-ONE.
PERFORM OPEN-CURSOR
PERFORM FETCH-CURSOR
PERFORM VARYING I FROM 1 BY 1 UNTIL SQLCODE = DB2EOT
do stuff here...
END-PERFORM
COMPUTE WS-SUB = I + 0
PERFORM CLOSE-CURSOR
... do another loop using WS-SUB ...
我想知道为什么COMPUTE WS-SUB = I + 0
行在那里。我的理解是I
将始终至少是1
,因为它上面的执行块(即,即使有一个 EOT 开始,I
将在初始迭代中设置为 1)。
甚至需要COMPUTE
行吗?它是否在做一些我不知道的隐式转换?为什么会在那里?你为什么不直接MOVE I TO WS-SUB
?
【问题讨论】:
它与 move 语句非常相似。我想知道他们为什么要加 0。语句“Compute WS-SUB = I”也能正常工作。 【参考方案1】:称其为愚蠢,但对于某些编译器(具有有效的正确选项),给定
01 SIGNED-NUMBER PIC S99 COMP-5 VALUE -1.
01 UNSIGNED-NUMBER PIC 99 COMP-5.
...
MOVE SIGNED-NUMBER TO UNSIGNED-NUMBER
DISPLAY UNSIGNED-NUMBER
结果:255。但是......
COMPUTE UNSIGNED-NUMBER = SIGNED-NUMBER + ZERO
结果:1(无符号)
因此,为了回答您的问题,这可以归类为一种将有符号数字转换为无符号数字的技术。但是,在您提供的代码示例中,它根本没有任何意义。
【讨论】:
我们也认为它没有多大意义。只是想确保没有一些我们没有想到的神秘施法约定。 @galador 听起来像是 1. 可能已经在某个时间签名(可疑),或者 2. 有人复制了代码并且没有注意他们复制的内容......【参考方案2】:请注意,“I”的定义(可能)由一位程序员编写,WS-SUB 由另一位程序员编写(命名不同,VALUE 子句出于相同目的而不同)。
Programmer 2 看起来像“老派”:PIC S9(4),签名并占用了所有“适合”半字的数字。根据可能的值范围,S9(9) 可能“远远超过顶部”,但程序员 1 根本不关心这些事情。
可能程序员 2 担心将 S9(9) COMP 用于需要(可能很多)少于 9999 个“事物”的事物。 “在不更改现有代码的情况下,我将‘高效’”。在我看来,该字段不太可能被定义为无符号。
具有九位数字的 COMP/COMP-4 在用于计算时确实会降低性能。尝试“添加 1”到 9(9) 和 9(8) 和 9(10) 并比较生成的代码。如果您可以有九位数字,请使用 9(10) 进行定义,否则使用 9(8) 定义,如果您需要完整字词。
程序员 2 对此有所了解。
带有 + 0 的 COMPUTE 可能是故意的。为什么程序员 2 会那样使用 COMPUTE(原问题)?
现在事情变得复杂了。
大型机上有两种“类型”的“二进制”字段:那些将包含受 PICture 子句限制的值(USAGE BINARY、COMP 和 COMP-4);那些包含受字段大小限制的值(USAGE COMP-5)。
使用 BINARY/COMP/COMP-4,字段的大小由 PICture 确定,因此可以保存的值也是如此。 PIC 9(4) 是一个半字,最大值为 9999。PIC S9(4) 是一个半字,其值为 -9999 到 +9999。
使用 COMP-5 (Native Binary),图片只是决定字段的大小,字段的所有位都与字段的值相关。图 9(1) 至 9(4) 定义半字,图 9(5) 至 9(9) 定义全字,图 9(10) 至 9(18) 定义双字。 PIC 9(1) 最多可以容纳 65535,S9(1) -32,768 到 +32,767。
一切顺利。然后是编译器选项TRUNC。这有三个选项。 STD、默认、BIN 和 OPT。
BIN 可以认为影响最深远。 BIN 使 BINARY/COMP/COMP-4 的行为类似于 COMP-5。实际上,一切都变成了 COMP-5。二进制字段的图片被忽略,除了确定字段的大小(奇怪的是,使用 ON SIZE ERROR,当超过 PICture 的最大值时“错误”)。 IBM Enterprise Cobol 中的 Native Binary 主要(但不限于)生成“最慢”的代码。截断是字段大小(半字、全字、双字)。
STD 默认是“标准”截断。这将截断为“图片”。因此,它是“十进制”截断。
OPT 用于“性能”。使用 OPT,编译器会以任何方式截断特定“代码序列”的最“高性能”。这可能意味着中间值和最终值可能具有“位设置”,这些“位”位于 PICture 的“范围之外”。但是,当用作源时,二进制字段将始终只反映 PICture 指定的值,即使设置了“多余”位。
在使用 OPT 时,重要的是所有二进制字段“符合 PICture”,这意味着代码绝不能依赖在 PICture 定义之外设置的位。
注意:即使使用了 OPT,OPTimizer(OPT(STD) 或 OPT(FULL))仍然可以提供进一步的优化。
这一切都很好。
但是,如果您“混合”TRUNC 选项,或者如果 CALLing 程序中的二进制定义与 CALLed 程序中的不同,则很容易出现“pickle”。如果同一运行单元中的模块使用不同的 TRUNC 选项编译,或者文件中的二进制字段使用一个 TRUNC 选项写入,然后使用另一个选项读取,则可能会发生“混合”。
现在,我怀疑 Programmer 2 遇到了这样的事情:要么,使用 TRUNC(OPT),他们注意到字段中的“多余位”并认为需要处理它们,或者,通过选项的“混合”在运行单元或“跨文件使用”中,他们注意到需要对其进行处理的“多余位”(即“删除混合”)。
程序员 2 开发了 COMPUTE A = B + 0 来“处理”特定问题(感知的或实际的),然后将其普遍应用到他们的工作中。
这是一种“猜测”,或者,更好的是,一种适用于已知信息的“合理化”。
这是一个“假”修复。没有问题(TRUNC(OPT) 的正常工作方式)或者正确的解决方案是跨模块/文件使用的 TRUNC 选项的“规范化”。
我不希望现在有很多人匆忙离开并将 COMPUTE A = B + 0 放入他们的代码中。首先,他们不知道自己为什么要这样做。对于延续,这是错误的事情。
当然,不要只是从您找到的任何这些中删除“+ 0”。如果存在“混合”TRUNC,则程序可能会停止“工作”。
在一种情况下,我对 BINARY/COMP/COMP-4 使用了“加零”。这是在一个“米老鼠”程序中,这个程序没有任何目的,只是为了尝试一些东西。在这里,我将它用作“欺骗”优化器的一种方法,否则优化器可能会看到不变的值,因此会生成代码以使用文字结果,因为所有值在编译时都是已知的。 (我从 PhilinOxford 获得的一种可能“更简洁”和更灵活的方法是在该领域使用 ACCEPT)。当然,有问题的代码并非如此。
【讨论】:
【参考方案3】:我想知道是否有源代码的测试版本
COMPUTE WS-SUB = I + 0
ON SIZE ERROR
DISPLAY "WS-SUB overflow"
STOP RUN
END-COMPUTE
当开发人员满意并清理时丢弃范围测试? MOVE 不允许声明性 SIZE 语句。这就是我所看到的一个原因。或者也许是开发人员使用 COMPUTE 移动的习惯,作为一个微妙的提醒,让他们质疑每一步都需要防御性代码?正如乔指出的那样,也许不知道 SIZE 子句在没有 + 0 的情况下同样有效吗?或者维护者因一个错误而苦苦挣扎,并且在测试后出现了从 1 到 0 的更正变化?
【讨论】:
COMPUTE A + B ON SIZE ERROR ... END-COMPUTE 应该可以工作。我从来没有使用过它,因为我总是让我的字段足够大以容纳指定的实际值,这与系统输入验证的内容背道而驰。 MOVE A TO B abd COMPUTE B = A 之间的区别在于为 COMPUTE 添加 ON SIZE ERROR 的可能性,而 MOVE 只是截断。 IF A GREATER THAN THAN 之前使用的商业价值应该否定 ON SIZE ERROR 的使用。以上是关于COBOL 将 0 添加到 COMPUTE 中的变量的主要内容,如果未能解决你的问题,请参考以下文章
如何从从 Assembly 返回到 COBOL 的指针中寻址数据缓冲区