COBOL中COMP-3值写入数据集后异常变更问题求助
已解决
我终于揪出这个诡异问题的根源了!在写入输出文件的代码后面,居然藏着一行我之前完全没留意到的代码:
INSPECT OUT-RECORD REPLACING ALL X'00' BY ' '
这行代码把所有X'00'替换成了X'40'(也就是空格的十六进制值),这就是那个神秘的'4'的由来!说起来真的有点哭笑不得,这简直就是COBOL版的“漏写分号”低级错误,完全是自己粗心没检查到所有代码导致的。
特别感谢Bruce和匿名用户user9835153的热心帮忙!
原问题
我最近碰到一个特别奇怪的COBOL问题,折腾了好久都没头绪,只好来求助大家。
我的需求很明确:把输入的无符号zoned decimal数值(PIC定义为9(3).9(6))转换成带符号的COMP-3类型(PIC定义为S9(3)V9(6))写入输出数据集。大部分值转换都很正常,但只要输入中小数点前后都是0的时候,小数点前的0总会莫名其妙变成4。
具体示例
- 输入值为31.006261时,写入结果完全正常:+31.006261(输出文件中实际存储为x'031006261C')
- 可输入值为30.006261时,结果就变成了+34.006261(输出文件实际存储为x'034006261C')
我没法修改输入数据的格式,但可以调整输入布局。为了排查问题,我试了好几种值传递的方式:
- 直接将输入字段移动到COMP-3输出字段
- 先把输入值移到工作存储区的临时字段,再转存到输出字段
- 把输入设为字符字段,忽略小数点后再转为数值
但不管用哪种方式,结果都一模一样,那个0还是会变成4。
简化后的测试代码
* 输入文件中的值30.006261被读入WS-IN-VAL 01 WS-IN-RECORD. 05 WS-IN-VAL PIC 9(3).9(6). 01 OUT-RECORD. 05 WS-OUT-VAL PIC S9(3)V9(6) COMP-3. * 工作存储区 01 area 05 WS-HOLD-VAL PIC 9(3)V9(6). 05 WS-DISP-VAL PIC +9(3).9(6). MOVE WS-IN-VAL TO WS-HOLD-VAL. MOVE WS-HOLD-VAL TO WS-OUT-VAL. MOVE WS-OUT-VAL TO WS-DISP-VAL. WRITE WS-OUT-RECORD. DISPLAY 'VALUE IN: ' WS-IN-VAL. DISPLAY 'HOLD VALUE: ' WS-HOLD-VAL. DISPLAY 'VALUE OUT: ' WS-OUT-VAL. DISPLAY 'FORMATTED: ' WS-DISP-VAL.
显示层面的测试输出
从DISPLAY语句得到的结果看起来完全正常:
VALUE IN: 30.006261 HOLD VALUE: 030006261 VALUE OUT: 030006261 FORMATTED: +030.006261
但当我用HEX ON模式打开输出文件时,结果就不对了:
----+ 04021 3066C
用布局工具查看文件时,显示的是:+34.006261。
更多测试验证
我特意准备了8条测试记录,一半改成10.1xxxxx格式,另一半改成10.0xxxxx格式(x为任意数字):
- 所有10.0xxxxx的记录都变成了14.0xxxxx
- 10.1xxxxx的记录则完全正常
我还测试了20.x、30.x、40.x等情况,结果一致——只要小数点前后是0,前面的0就会被替换成4。
我甚至试过用COMPUTE替代MOVE来完成无符号到带符号的转换,结果还是一样。为了排除小数点的影响,我还修改过输入布局,单独读取小数点并把它的十六进制值改成x'00',但也没用。现在我真的不知道该试什么了,也没找到有相同经历的人。
有没有大佬能告诉我,为什么小数点前的0会被替换成4?
2018年5月21日更新(根据建议调整后)
按照大家的建议修改后,测试输出如下:
VALUE FROM FILE: 50.022287 VALUE AFTER MOVE: 050022287 VALUE AS COMP-3 (OUTPUT FLD): 050022287 OUTPUT DISPLAYED: +050.022287 VALUE IN FILE: +54.022287
遗憾的是,写入数据集后,小数点前的0还是会变成4。
内容的提问来源于stack exchange,提问作者J.Turner

