当我将PIC X
中的数字移动到PIC 9
时,数字字段的值为0.
FOO
,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
。
答案 0 :(得分:4)
COBOL中的数据移动是一个复杂的主题 - 但现在是 简要回答您的问题。一些数据移动规则 是直截了当的,符合人们的期望。其他人有些吵闹,可能会有所不同 编译器选项,供应商以及可能的COBOL标准版本(74,85,2002)。
考虑到上述情况,以下是对您的示例中发生的事情的解释。
什么东西'大'是 MOVEd必须发生'小'截断。这是当BAR被移动到FOO时发生的事情。怎么样 发生截断由接收项决定 数据类型。当接收项是字符数据(PIC X)时,最右边的字符将从发送字段中截断。 对于数字数据,最左边的数字将从发送字段中截断。对于所有COBOL,此行为几乎都是通用的 编译器。
作为这些规则的后果:
当一个以“1”开头,后跟一堆空格字符的长'X'字段(BAR)为MOVEd时
在最短的'X'字段中,最左边的字符被转移。这就是移动到另一个PIC X
时保留'1'的原因
项目
当长'X'字段(BAR)移动到'9'(数字)数据类型时,最先移动最右边的字符。这就是为什么'1'丢失了,从来没有 移动了,BAR中的最后两个空格是。
到目前为止足够简单......接下来的一点比较复杂。究竟发生了什么是供应商,版本,编译器选项和字符集
具体。对于本示例的其余部分,我将假设正在使用EBCDIC字符集和IBM Enterprise COBOL编译器。一世
还假设你的程序显示 b 0而不是0 b 。
如果PIC X
字段仅包含数字,则将PIC 9
数据移至PIC X
字段在COBOL中具有普遍合法性。最
COBOL编译器在确定其数值时仅查看PIC 9
字段的低4位。一个例外是最少的
存储符号或缺少符号的有效数字。对于无符号数字,最低有效数字的高4位
作为MOVE的结果被设置为1(十六进制F)(强制遵循对有符号字段的不同规则)。低4位是没有MOVEd
强迫。那么,当空格字符移动到PIC 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
最后的话......最好不要对此事有任何了解。不要编写依赖于模糊截断的程序 规则和/或数据类型强制。在你正在做的事情上要准确明确。
答案 1 :(得分:3)
首先,为什么认为将400字节字段移动到双字节字段可能有用?你将得到一个“截断”的“一定量(!)”(并且截断量是确定的,为398字节)。你知道吗你的400字节的部分会被截断吗?我猜不会。
对于字母数字“发送”项(您拥有的),使用的(最大)字节数是数字字段中的最大字节数(18/31,具体取决于编译器/编译器选项)。这些字节取自字母数字字段的 right 。
因此,您已将最右边的 18/31位数移动到两位数的接收字段。您已经解释过您有“1”和399个空格,因此您的两位数字字段有MOVEd 18/31空格。
您的数字字段为“无符号”(PIC 9(2)不是PIC S9(2)或带有单独符号)。对于无符号字段(具有“无操作符号”的字段),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个空格(如您所料)和 space ,然后是第二个字段的零,这是您没想到的
如果您想在操作中明确看到这一点:
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字母数字到数字中,它是字母数字的最右边字节,它们实际上是先移动的;
“无符号”数字应该/必须始终保持无符号;
始终检查编译器诊断并更正代码,以便不产生诊断(如果可能);
在显示示例时,显示计算机生成的实际结果非常重要,而不是人类解释的结果。 “0”不相同,“0”与“0”不同。
IGYPG3112-W字母数字或国家发送字段“FOO”超过18位。最右边的18个字符用作发件人。
注意,“18位数”将是“31位数”,编译器选项ARITH(EXTEND)。
尽管它只是一个低级的“W”,它只给出了4的返回码,而不是在阅读它是不好的做法,如果你读过它,你就不需要问这个问题 - 尽管也许你还不知道你是怎么得到“0”的,但这是另一回事。
答案 2 :(得分:1)
我认为你希望9(2)值显示为“1”而不是“0”,你会为什么不这样做而感到困惑?
当您从X值移动时,您将从左向右移动值(除非目标值改变了事物)。所以9值有一个空格。为了简化它,将“X(2)值'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测试也会失败...