You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

GNU COBOL实现的Quick Sort返回无效结果问题排查

GNU COBOL 3.2.2 递归快速排序异常问题排查

问题描述

我基于标准快速排序逻辑,在GNU COBOL 3.2.2中用递归子程序实现排序,这套逻辑在C、Python等语言中运行正常,但在COBOL中执行后,数组排序结果常出现无效值。数组已被完全填充有效数据,递归逻辑看起来无明显错误,怀疑问题源于GNU COBOL对以下特性的特殊处理:

  • 递归子程序调用机制
  • 数组按引用传递方式
  • DEPENDING ON动态数组的处理
  • 运行时内存布局

完整代码示例

主程序 quick_sort.cbl

IDENTIFICATION DIVISION.
       PROGRAM-ID. QUICK-SORT-MAIN.
       DATA DIVISION.
       WORKING-STORAGE SECTION.
       01 ARRAY-SIZE PIC 9(4) VALUE 1000.
       01 UNSORTED-ARRAY.
           05 ARRAY-ELEMENT PIC 9(4) OCCURS 1 TO 9999 DEPENDING ON ARRAY-SIZE.
       01 START-TIME PIC 9(18).
       01 END-TIME PIC 9(18).
       01 ELAPSED-TIME PIC 9(18).
       PROCEDURE DIVISION.
           CALL "GETMICROSEC" USING START-TIME.
           * 填充数组逻辑(确保数组已完全填充有效数据)
           CALL "QUICK-SORT-SUB" USING UNSORTED-ARRAY, 1, ARRAY-SIZE.
           CALL "GETMICROSEC" USING END-TIME.
           COMPUTE ELAPSED-TIME = END-TIME - START-TIME.
           DISPLAY "排序完成,耗时:" ELAPSED-TIME "微秒".
           STOP RUN.

递归子程序 quick_sort_sub.cbl

IDENTIFICATION DIVISION.
       PROGRAM-ID. QUICK-SORT-SUB RECURSIVE.
       DATA DIVISION.
       LINKAGE SECTION.
       01 SORT-ARRAY.
           05 ARRAY-ELEMENT PIC 9(4) OCCURS 1 TO 9999 DEPENDING ON ARRAY-SIZE.
       01 LOW PIC 9(4).
       01 HIGH PIC 9(4).
       01 ARRAY-SIZE PIC 9(4).
       WORKING-STORAGE SECTION.
       01 I PIC 9(4).
       01 J PIC 9(4).
       01 PIVOT PIC 9(4).
       01 TEMP PIC 9(4).
       PROCEDURE DIVISION USING SORT-ARRAY, LOW, HIGH.
           IF LOW >= HIGH
               EXIT PROGRAM.
           MOVE LOW TO I.
           MOVE HIGH TO J.
           MOVE ARRAY-ELEMENT(I) TO PIVOT.
           PERFORM UNTIL I >= J
               PERFORM UNTIL ARRAY-ELEMENT(I) > PIVOT OR I >= HIGH
                   ADD 1 TO I
               END-PERFORM.
               PERFORM UNTIL ARRAY-ELEMENT(J) < PIVOT OR J <= LOW
                   SUBTRACT 1 FROM J
               END-PERFORM.
               IF I < J
                   MOVE ARRAY-ELEMENT(I) TO TEMP
                   MOVE ARRAY-ELEMENT(J) TO ARRAY-ELEMENT(I)
                   MOVE TEMP TO ARRAY-ELEMENT(J)
           END-PERFORM.
           MOVE ARRAY-ELEMENT(J) TO ARRAY-ELEMENT(LOW)
           MOVE PIVOT TO ARRAY-ELEMENT(J).
           CALL "QUICK-SORT-SUB" USING SORT-ARRAY, LOW, J - 1.
           CALL "QUICK-SORT-SUB" USING SORT-ARRAY, J + 1, HIGH.
           EXIT PROGRAM.

计时函数 getmicrosec.cpp

#include <sys/time.h>
extern "C" void getmicrosec(long long *time) {
    struct timeval tv;
    gettimeofday(&tv, NULL);
    *time = (long long)tv.tv_sec * 1000000 + tv.tv_usec;
}

编译命令

# 编译C计时函数
g++ -c getmicrosec.cpp -o getmicrosec.o
# 编译COBOL子程序
cobc -c quick_sort_sub.cbl -o quick_sort_sub.o
# 编译主程序并链接
cobc quick_sort.cbl quick_sort_sub.o getmicrosec.o -o quick_sort -x

问题排查与解决方向

  • 动态数组大小未传递:递归子程序的LINKAGE SECTION中,ARRAY-SIZE是动态数组的依赖变量,但主程序调用时未传递该值,导致子程序无法确定数组实际有效长度,访问时易触发内存越界。解决方法:在主程序调用时添加ARRAY-SIZE作为参数,确保子程序能正确获取数组边界。
  • 递归栈溢出:当数组规模较大时,GNU COBOL默认递归栈大小可能不足以支撑多层调用,引发栈溢出破坏数据。可通过编译选项-fstack-size=4096(根据实际需求调整数值)增大栈空间。
  • 数组索引越界:COBOL数组索引从1开始,递归调用时J-1可能得到0,导致下一层调用索引非法;循环中I >= HIGH的判断逻辑存在漏洞,可能导致访问超出数组有效范围。需在递归调用前检查LOW < J-1再执行,同时调整循环终止条件确保索引始终在1到数组大小之间。
  • 添加调试输出:在 pivot 选择、元素交换、递归前后等关键步骤添加DISPLAY语句,输出当前I、J、PIVOT及对应位置的数组元素值,定位数据异常的触发时机,排查具体逻辑错误。

内容的提问来源于stack exchange,提问作者TranTrung

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.12 01:50:55