我有两个 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)
任何人都可以解释一下似乎有什么问题吗?
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位整数,但Cint
是32位(请参阅相同的链接文档).
您需要:
BINARY-LONG
(或 BINARY-INT
)类型;short
类型作为参数和返回类型。就目前情况而言,您的 C 函数正在将 32 位写入(或尝试写入)到仅保证大小为 16 位的位置;这是“未定义的行为”,并且更有可能是错误的原因。 [你只是(不)幸运,在 func1
通话中,UB 没有触发违规行为!]