我让C和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

第一个函数可以工作,但第二个函数会生成错误:

try 引用未分配的内存(信号SIGSEGV) 全额输出

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

attempt to reference unallocated memory (signal SIGSEGV)

有人能解释一下问题出在哪里吗?

推荐答案

您在COBOL源代码中声明的变量类型(USAGE)与C源代码中的变量类型不兼容.

首先,GnuCobol中的BINARY-DOUBLE类型是64位的原生integer.从GnuCOBOL Programmer’s Guide人开始:

BINARY-DOUBLE [ SIGNED ]
~~~~~~~~~~~~~

        Range of Values: -9,223,372,036,854,775,808 – 9,223,372,036,854,775,807
        Storage Format: Native Binary Integer

如果您想要IEEE-754 64位浮点类型(就像Cdouble一样),那么您想要的是FLOAT-LONG.来自同一文档:

FLOAT-LONG
~~~~~~~~~~

        Range of Values: Approx. -1.797693134862316 * 10308 – 1.797693134862316 * 10308
        Storage Format: Native IEEE 754 Binary64 Floating-point

然而,我看不出这本身会导致报告的SIGSEGV错误,因为两个内存‘单位’具有相同的大小(尽管传递的a值将被解释为无意义的double).

更有可能导致内存冲突的是,int个参数的类型也是错误的:BINARY-SHORT16 bit个整数,但Cint32 bits(参见相同的链接文档).

您需要:

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

按照现在的情况,您的C函数正在将32位写入(或attempting写入)到一个只保证16位大小的位置;这是undefined behaviour,更有可能是错误的原因.[你只是(不)幸运,在func1呼叫中,UB没有触发内存违规!]

C++相关问答推荐

ARM上的Modulo Sim Aarch 64(NEON)

C中空终止符后面的数字?

C:gcc返回多个错误定义,但msvc—不""'

什么C代码将确定打开的套接字正在使用的网络适配器?

如何在Visual Studio代码中关闭此函数名称显示功能?

C语言中的strstr问题

我可以在C中声明不同长度数组的数组而不带变量名吗?

使用AVX2的英特尔2022编译器的NaN问题&;/fp:FAST

Linux不想运行编译后的文件

在Linux上使用vscode和lldb调试用Makefile编译的c代码

将字符串数组传递给C中的函数:`str[dim1][str_size]`vs`*str[dim1]`

使用正则表达式获取字符串中标记的开始和结束

不带Malloc的链表

变量值不正确的问题

`%%的sscanf无法按预期工作

无法将字符串文字分配给 C 中的字符数组

函数的typedef是标准 C 语法吗?它与函数指针的typedef有何不同?

malloc 属性不带参数

使用fread()函数读取txt文件

在带中断的循环缓冲区中使用 易失性