GnuCobol 使用 double 类型的参数调用 C 函数

问题描述 投票:0回答:1

我有两个 C 函数做完全相同的事情 区别在于它们的返回类型和第一个参数类型

int func1(int a, int *b) {
    if (a > 0) {
        *b = 0;
        return 1;
    }

    *b = -1;
    return 0;
}

double func2(double a, int *b) {
    if (a > (double)0.0) {
        *b = 0;
        return 1.0;
    }

    *b = -1;
    return (double)0.0;
}

将它们编译到库中

gcc -c -static -o testlib.o testlib.c

遵循 Cobol 代码调用这两个函数

       IDENTIFICATION DIVISION.
       PROGRAM-ID. CallCFunctions.
       
       ENVIRONMENT DIVISION.

       DATA DIVISION.
       WORKING-STORAGE SECTION.
       01  VAR-AI USAGE BINARY-SHORT SIGNED.
       01  VAR-BI USAGE BINARY-SHORT SIGNED.
       01  VAR-CI USAGE BINARY-SHORT SIGNED.
       
       01  VAR-AD USAGE BINARY-DOUBLE.
       01  VAR-BD USAGE BINARY-DOUBLE.
       01  VAR-CD USAGE BINARY-DOUBLE.
       

       PROCEDURE DIVISION.
           
           MOVE 1 TO VAR-AI.
           MOVE -10 TO VAR-BI.
           MOVE ZERO TO VAR-CI.
           CALL "func1" USING BY VALUE VAR-AI BY REFERENCE VAR-BI
               RETURNING VAR-CI
           DISPLAY "Calling 'func1'".
           DISPLAY "A = ", VAR-AI, " B = ", VAR-BI, " C = ", VAR-CI

           MOVE 1 TO VAR-AD.
           MOVE -10 TO VAR-BD.
           MOVE ZERO TO VAR-CD.
           CALL "func2" USING BY VALUE VAR-AD BY REFERENCE VAR-BD
               RETURNING VAR-CD
           DISPLAY "Calling 'func2'".
           DISPLAY "A = ", VAR-AD, " B = ", VAR-BD, " C = ", VAR-CD


       STOP RUN.

编译 Cobol 代码

cobc -x -free -o test test.cbl testlib.o

第一个函数有效,第二个函数返回错误

attempt to reference unallocated memory (signal SIGSEGV)

全力输出

Calling 'func1'
A = +00001 B = +00000 C = +00001
Calling 'func2'

attempt to reference unallocated memory (signal SIGSEGV)

任何人都可以解释一下似乎有什么问题吗?

c cobol gnucobol
1个回答
0
投票

COBOL 源中声明的变量类型 (

USAGE
) 与 C 源中的变量类型不兼容。

首先,GnuCobol 中的

BINARY-DOUBLE
类型是 64 位原生 integer。来自本文档

二进制双精度 [ 有符号 ]
~~~~~~~~~~~~~

值范围:-9,223,372,036,854,775,808 – 9,223,372,036,854,775,807
存储格式:本机二进制整数

如果您追求 IEEE-754 64 位浮点类型(C

double
也是如此),那么您想要的是
FLOAT-LONG
。来自同一份文件:

浮动长
~~~~~~~~~~

值范围:大约。 -1.797693134862316 * 10308 – 1.797693134862316 * 10308
存储格式:本机 IEEE 754 Binary64 浮点

但是,我看不出这本身会导致报告的

SIGSEGV
错误,因为两个内存“单元”具有相同的大小(尽管传递的
a
值将被解释为无意义
double
).

更可能导致内存违规的是

int
参数的类型也是错误的:
BINARY-SHORT
是一个16位整数,但C
int
32位(请参阅相同的链接文档).

您需要:

  1. 在 COBOL 代码中使用
    BINARY-LONG
    (或
    BINARY-INT
    )类型;
  2. 或者在 C 代码中使用
    short
    类型作为参数和返回类型。

就目前情况而言,您的 C 函数正在将 32 位写入(或尝试写入)到仅保证大小为 16 位的位置;这是“未定义的行为”,并且更有可能是错误的原因。 [你只是(不)幸运,在 func1 通话中,UB 没有触发违规行为!]

    

© www.soinside.com 2019 - 2024. All rights reserved.