I need to call a function written in C from a GNU COBOL program which returns a 64 bit integer (BINARY-DOUBLE
in COBOL). However, it seems like GNU COBOL assumes that the return value is always BINARY-LONG
, which means the return value is messed up.
Of course, the obvious solution would be to "return" the value by passing a reference to where I want the C function to put it, but I can't change the original C function. I could write a wrapper in C, but it seems annoying to do that every time I need call a function with a 64-bit return value, so I'm wondering if there's a way to do this within COBOL.
CodePudding user response:
Of course, I figured it out immediately after posting. The solution is just to store the return value in a pointer. Using REDEFINES
, we can make a pointer that overlaps our 64-bit integer. In effect, this is basically the same thing as returning directly into the integer. Example:
ext.c
:
#include <stdint.h>
uint64_t testfun() {
return 0x1213141516171819;
}
main.cob
:
IDENTIFICATION DIVISION.
PROGRAM-ID. main-prog.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 retint USAGE BINARY-DOUBLE UNSIGNED.
01 retval REDEFINES retint USAGE POINTER.
PROCEDURE DIVISION.
CALL STATIC "testfun" RETURNING retval.
DISPLAY "retval: " retval.
DISPLAY "retint: " retint.
STOP RUN.
CodePudding user response:
The "standard COBOL" solution is to use call-prototypes so the compiler does know exactly what the parameters look like (think of it as a C header).
But support for this is lacking in many COBOL compilers in use and (up to today) is also lacking in GnuCOBOL - the return size is not taken into account.
While this implementation is likely to change: GnuCOBOL currently only "returns" to one of:
- default: C
int
CALL ... RETURNING NOTHING
orRETURNING OMITTED
:void
CALL ... RETURNING ADDRESS OF
orRETURNING pointer-item
:void *
- machine pointer - while using this is not portable COBOL using the later andREDEFINE
it with a 64bit integer or the other way around as mentioned in the other answer will work using GnuCOBOL on 64bit machines (at least on all machines that do have a pointer size of exact 64bit or have a bigger native pointer size and store both pointer and integers in big-endian format)