3

当我将 a 中的数字移动PIC X到 aPIC 9时,数字字段的值为 0。

FOO, a PIC X(400), 在第一个字节中具有“1”,在剩余的 399 中具有空格。进入PIC 9(02) BAR类似这样

DISPLAY FOO
MOVE FOO to BAR
DISPLAY BAR

产量

1
0

为什么 BAR 是 0 而不是 1?[编辑:最初,'发生了什么?']

后记:NealB 说:“不要编写依赖于晦涩的截断规则和/或数据类型强制的程序。在你所做的事情上要精确和明确。”

这让我意识到我真的想要COMPUTE BAR AS FUNCTION NUMVAL(FOO)包裹在一个NUMERIC测试中,而不是一个MOVE.

4

3 回答 3

6

COBOL 中的数据移动是一个复杂的主题 - 但这里是您问题的简化答案。一些数据移动规则是直截了当的,并且符合人们的预期。其他的有些奇怪,可能会因编译器选项、供应商以及可能在 COBOL 标准的版本之间而有所不同(74、85、2002)。

考虑到上述内容,这里是对您的示例中发生的事情的解释。

当“大”的东西被移动到“小”的东西中时,必须发生截断。这就是将 BAR 移至 FOO 时发生的情况。截断的发生方式取决于接收项目数据类型。当接收项目是字符数据(PIC X)时,最右边的字符将从发送字段中被截断。对于数字数据,最左边的数字从发送字段中被截断。对于所有 COBOL 编译器,这种行为几乎是通用的。

作为这些规则的结果:

  • 当以“1”开头的长“X”字段(BAR)后跟一堆空格字符被移动到较短的“X”字段中时,最左边的字符被转移。PIC X 这就是为什么在移动到另一个项目时会保留“1”的原因。

  • 当长“X”字段(BAR)移动到“9”(数字)数据类型时,最右边的字符首先移动。这就是为什么“1”丢失了,它从未被移动过,BAR 中的最后两个空格被移动了。

到目前为止很简单......下一点更复杂。究竟会发生什么是供应商、版本、编译器选项和特定的字符集。对于本示例的其余部分,我将假设使用 EBCDIC 字符集和 IBM Enterprise COBOL 编译器。我还假设您的程序显示b 0 而不是 0 b

在 COBOL 中,只要字段仅包含数字,将PIC X数据移动到字段是普遍合法的。大多数 COBOL 编译器在确定其数值时只查看字段的低 4 位。一个例外是存储符号或缺少符号的最低有效位。对于无符号数字,作为 MOVE 的结果,最低有效数字的高 4 位设置为 1(十六进制 F)(强制遵循有符号字段的不同规则)。低 4 位在没有强制的情况下被移动。那么,当一个空格字符被移动到一个PIC 9PIC XPIC 9PIC 9场地?SPACE 的十六进制表示是 '40' (ebcdic)。高 4 位“4”被翻转为“F”,低 4 位按原样移动。这导致包含“F0”十六进制的最低有效数字 (lsd)。这恰好是PIC 9数据项中数字“0”的无符号数字表示。其余的前导数字按原样移动(即“40”十六进制)。最终结果是 FOO 显示为 b 0。但是,如果您要执行除“移动”或“显示”FOO 之外的任何操作,则剩余“数字”的高 4 位可能会被强制为零。这会将它们的显示特性从空格翻转为零。

以下示例 COBOL 程序及其输出说明了这些要点。

   IDENTIFICATION DIVISION.
   PROGRAM-ID. EXAMPLE.
   DATA DIVISION.
   WORKING-STORAGE SECTION.
   01.
       05 BAR        PIC X(10).
       05 FOO        PIC 9(2).
       05 FOOX       PIC X(2).
   PROCEDURE DIVISION.
       MOVE '1         ' TO BAR
       MOVE BAR TO FOO
       MOVE BAR TO FOOX
       DISPLAY 'FOO : >' FOO '< Leftmost trunctaion + lsd coercion'
       DISPLAY 'FOOX: >' FOOX '< Righmost truncation'
       ADD ZERO TO FOO
       DISPLAY 'FOO : >' FOO '< full numeric coercion'
       GOBACK
       .

输出:

FOO : > 0< Leftmost trunctaion, lsd coercion
FOOX: >1 < Righmost truncation
FOO : >00< full numeric coercion

最后的话……最好不要对这种事情一无所知。不要编写依赖于晦涩的截断规则和/或数据类型强制的程序。在你正在做的事情上要准确和明确。

于 2013-05-21T17:44:39.333 回答
4

首先,您为什么认为将 400 字节字段移动到 2 字节字段可能有用?您将获得“截断”的“一定数量(!)”(并且截断的数量是确定的,为 398 字节)。你知道400 字节的一部分会被截断吗?我猜不会。

对于字母数字“发送”项目(您拥有的),使用的(最大)字节数是数字字段中的最大字节数(18/31,取决于编译器/编译器选项)。这些字节取自字母数字字段的右侧

因此,您已将最右边的18/31 位移动到两位数接收字段。您已经解释过您有“1”和 399 个空格,因此您已将 18/31 个空格移动到您的两位数字字段中。

您的数字字段是“无符号”(PIC 9(2) 不是 PIC S9(2) 或带有 SIGN SEPARATE)。对于无符号字段(即“无操作符号”的字段),COBOL 编译器生成代码以确保该字段不包含符号。

此代码会将 PIC 9(2) 中最右边的空间变成“0”,因为 ASCII 空间是 X'20',EBCDIC 空间是 X'40'。“符号”嵌入在 USAGE DISPLAY 数字字段的最右边字节中,并且在 MOVE 期间除了符号之外没有其他数据发生变化。X'2n' 或 X'4n' 的 2 或 4 不考虑其值,被“无符号”(缺少“操作符号”)的位模式消除。一个“无符号”后跟一个数字(即空格中剩下的“0”)显然会显示为零。

现在,您为 400 字节字段显示一个“1”,为您的两字节数字显示一个 0。

我要做的是:

DISPLAY
   ">"
   the-first-field-name
   "<"
   ">"
   the-second-field-name
   "<"
   ...

或者

DISPLAY
   ">"
   the-first-field-name
   "<"
DISPLAY
   ">"
   the-second-field-name
   "<"
   ...

如果你这样做了,你应该会发现 1 后跟 399 个空格作为你的第一个字段(正如你所期望的)和空格后跟零作为你的第二个字段,这是你没想到的。

如果您想具体查看此操作:

FOO PIC X(400) JUST RIGHT.

MOVE "1" TO FOO
MOVE FOO TO BAR
DISPLAY
   ">"
   FOO
   "<"
DISPLAY
   ">"
   BAR
   "<"

你应该看到你“几乎”期望的东西。您可能还需要前导零(级别编号 05 是一个示例,您使用的任何级别编号都可以使用)。

05  BAR PIC 99.
05  FILLER REDEFINES BAR.
    10  BAR-FIRST-BYTE PIC X.
        88  BAR-FIRST-BYTE-SPACE VALUE SPACE.
    10  FILLER PIC X.
...
IF BAR-FIRST-BYTE-SPACE
    MOVE ZERO TO BAR-FIRST-BYTE
END-IF

根据您的编译器以及它与 ANSI 标准(以及哪个 ANSI 标准)的接近程度,您的结果可能会有所不同(如果是这样,请尝试获得更好的编译器),但是:

不要将长度超过数字的最大值的字母数字移动到数字;
请注意,在 MOVE alpha-numeric to numeric中,实际上首先移动的是字母-数字的最右边的字节;
“无符号”数字应该/必须始终保持无符号;
始终检查编译器诊断并更正代码,以便不产生诊断(如果可能);在显示示例时,显示计算机产生的实际
结果 非常重要,而不是人类解释的结果。“0”不等于“0”不等于“0”。

编辑:看看 TS 的其他问题,我认为 Enterprise COBOL 是一个安全的选择。此消息将由编译器发出:

IGYPG3112-W 字母数字或国家发送字段“FOO”超过 18 位。最右边的 18 个字符被用作发送者。

请注意,使用编译器选项 ARITH(EXTEND) 时,“18 位”将是“31 位”。

尽管它是一个低级的“W”,它只给出一个返回码 4,但不费心去阅读它不是一个好习惯,如果你读过它,你就不需要问这个问题——尽管也许你会仍然不知道你是如何以“0”结束的,但那是另一回事。

于 2013-05-18T08:05:52.380 回答
2

我收集到您希望 9(2) 值显示为“1”而不是“0”,您对它为什么不显示感到困惑?

当您从 X 值移动时,您将值从左向右移动(除非目标值发生变化)。所以 9 值中有一个空格。为简化起见,将“X(2) value '1'”移动到 9(2) 值实际上会移动这些字符。该空格使 9(2) 中的内容无效,因此 COBOL 编译器使用它执行它知道的操作,返回 0。换句话说,定义 9(2) 告诉编译器解释一种不同的方式。

如果您希望 9(2) 显示为“1”,则必须以正确的方式将数据呈现给 9(2)。值为 1 的 9(2) 具有字符“01”。未经测试:

03  FOO       PIC X(2) value '1'.
03  TEXT-01   PIC X(2) JUSTIFIED RIGHT.
03  NUMB-01 REDEFINES TEXT-01 PIC 9(2).
03  BAR       PIC 9(2).

DISPLAY FOO.
MOVE FOO TO TEXT-01.
INSPECT TEXT-01 REPLACING LEADING ' ' BY '0'. 
MOVE NUMB-01 TO BAR.
DISPLAY BAR.

在您的示例中对 BAR 使用 NUMERIC 测试也应该失败......

于 2013-05-18T03:07:56.570 回答