Home > Software design >  Getting a 64 bit return value from a C function in GNU COBOL
Getting a 64 bit return value from a C function in GNU COBOL

Time:07-30

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 or RETURNING OMITTED: void
  • CALL ... RETURNING ADDRESS OF or RETURNING pointer-item: void * - machine pointer - while using this is not portable COBOL using the later and REDEFINE 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)
  • Related