2013-05-18 40 views
2

当我在PIC XPIC 9数值字段的值移动的数为0。这个字母数字到数字移动有什么问题?

FOO,一个PIC X(400),在剩余的399的第一个字节和间隔移动到PIC 9(02)BAR等具有“1”所以

DISPLAY FOO 
MOVE FOO to BAR 
DISPLAY BAR 

产生

1 
0 

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

后记:NealB说:“不要编写依赖于模糊截断规则和/或数据类型强制转换的程序。

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

+0

您使用哪种COBOL和OS? –

+0

您不可能在400字节的字段上使用NUMVAL。加上你的语法“AS FUNCTION”是不熟悉的。您不能将FOO定义/子定义/重新定义为小于或等于您可以拥有的最大数字位数(即18或31)的数值。请记住NUMVAL不喜欢非数字数据。 –

回答

3

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

考虑到上述情况,下面是对您的示例中发生的事情的解释。

当某些'大'是 MOVEd到'小'截断必须发生。这是当BAR被移动到FOO时发生的情况。 如何发生截断取决于接收项目 数据类型。当接收项目是字符数据(PIC X)时,最右边的字符将从发送字段中截断。 对于数字数据,最左边的数字从发送字段中截断。对于所有COBOL 编译器来说,这种行为非常普遍。

由于这些规则consequense:

  • 当长“X”字段(BAR)开始,接着一串空格字符“1”被移动 成一个较短的“X”字段传送最左边的字符。这就是为什么移动到另一个PIC X 项目时将保留'1'的原因。

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

到目前为止很简单...下一个比较复杂。具体发生的是供应商,版本,编译器选项和字符集 。对于本例的其余部分,我将假设使用EBCDIC字符集和IBM Enterprise COBOL编译器。我 也假定您的程序显示 b 0而不是0 b

在COBOL中将PIC X数据移动到PIC 9字段中时,只要PIC X字段仅包含数字,就是普遍合法的。大多数 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位可能会被强制为0,作为 的结果。这将把它们的显示特性从空间转换为零。

以下示例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 

最后的话......最好不要知道这种事情来什么。不要编写依赖于模糊规则和/或数据类型强制转换的程序。准确而明确地表达你在做什么。

+0

不错,从我这里起。一个疑问:“如果PIC X字段只包含数字*”,将PIC X数据移动到PIC 9字段在COBOL中是普遍合法的。无论内容如何,​​MOVE都是合法的,并且将会执行。稍后可能无法进行计算,但重要的是,它可能会出现一个大混乱:-) –

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. 

使用针对您的示例栏中数字测试应该会失败,以及...

+0

如果我没有记错(这已经很长时间了),那么如果源代码不是完全数字的,那么标准没有说明在X到9的移动中会发生什么,所以实现有权做任何它喜欢的事情。 – EJP

+0

如果字段长度相同,JUSTIFIED RIGHT不会产生效果。 JUSTIFIED正在为该MOVE使用PICture而不是数据。检查改变一个字节有点“过度杀伤”:-) –

+0

@BillWoodger好吧,就像我说的那样,它没有经过测试(尽管我在这里将它从一个经过测试的来源中解脱出来)。这个想法是将数据放在右侧而不是左侧。检查改变一个字节是矫枉过正,但我​​想我会继续,并展示如何处理它与多个字节。 :-) – Glenn1234

3

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

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

因此,您已将最右边的 18/31位移动到两位数的接收字段。你已经解释过你有“1”和399个空格,所以你的两位数字字段有18/31的空格。您的数值字段为“无符号”(PIC 9(2)而不是PIC S9(2)或SIGN SIGNALPARATE)。对于无符号字段(这是带有“无操作符号”的字段),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 
    "<" 
    ... 

如果你这样做了,你会发现后面399位为您的第一个字段1(如你所期望的)和空间紧随其后的零为你的第二个领域,你没有想到。

如果你想明确看到这个操作:

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字母数字长于最大数字可以是数字;
请注意,在MOVE字母数字到数字中,最右边的字节实际上是先移动的字母数字;
“无符号”数字应始终保持无符号;
始终检查编译器诊断并更正代码,以免产生诊断(如果可能);
当显示示例时,显示计算机生成的实际结果而不是人类解释的结果非常重要。 “0”与“0”不一样“0”不一样。

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

IGYPG3112-W字母数字或国内发送字段“FOO”超过了18位数字。最右边的18个字符用作发件人。

注意,“18位数”应该是编译器选项ARITH(EXTEND)的“31位数”。

即使它是一个只给出4的返回代码的低级“W”,也不会烦恼去阅读它,这不是一个好习惯,如果你已经阅读过它,你不需要问这个问题 - 尽管也许你仍然不知道你是以“0”结尾的,但那是另一回事。