action.skip

Calling C from COBOL

CALLing a C program from a COBOL program does not require any special coding convention.

Please note, however, that unlike C, text arguments passed as parameters from COBOL are not terminated by the null character (i.e., `\0'). Hence, the CALL’ed C function cannot rely on the existence of this termination character unless the COBOL code has been specifically written with interfacing with C in mind, and the termination characters have been set explicitly.

The example below uses hard-coded text values, 6 characters in length. When passing data items in which text length can be variable, it can be helpful to pass length information in a separate parameters.

Note

Some of the sample C programs in this section are compiled with cobc.

Remember that cobc translates COBOL into C, and then invokes the local C compiler. When cobc detects that the target file is written in C, it skips the preprocessing and translation steps, and proceeds directly to invoking the host C compiler with certain default settings.

Thus, the command cobc –c say.c differs from the command cl –c say.c in that cobc also applies certain default settings to the C compiler. There are times when this will be convenient, and times when it won’t. The user always has the option of using their C compiler to compile the C programs in these samples. But, it is important to understand that the commands cobc –c and cl –c (Windows) are not equivalent, as the use of cobc does apply additional compiler flags.

Static linking COBOL programs with C programs

The COBOL program

       IDENTIFICATION DIVISION.
       PROGRAM-ID. Hello.
       ENVIRONMENT DIVISION.
       DATA DIVISION.
       WORKING-STORAGE SECTION.
       01 HELLO PIC X(6) VALUE "Hello ".
       01 WORLD PIC X(6) VALUE "World!".
       PROCEDURE DIVISION.
       CALL "say" USING HELLO WORLD.
       STOP RUN.

Compile the COBOL program

In Linux/Unix, and Windows:

>cobc -c -static hello.cbl

The -static command-line option ensures that calls will be translated to plain static C function calls.

Note that when CALL’ing a C routine from a COBOL program, case-sensitivity must be respected. That is, if you were to try to reproduce this sample, while not respecting case-sensitivity, with a statement CALL SAY using HELLO, WORLD., then when you linked the two object files together into the executable hello.exe, you would receive an Unresolved external symbol error at link time:

       hello.obj : error LNK2019: unresolved external symbol SAY referenced in function
       Hello_
       hello.exe : fatal error LNK1120: 1 unresolved externals

To resolve this, you would have to change the CALL statement, to CALL say….

The C program

Note

For this sample the Unix versions and Windows versions of say.c differ in the function prototype declaration.

In Unix:

int say(char *hello, char *world)

In Windows:

       __declspec(dllexport) int say(char *hello, char *world)

       /* say.c Unix Version */
       int say(char *hello, char *world)
      {
       int i;
       for (i = 0; i < 6; i++)
       putchar(hello[i]);
       for (i = 0; i < 6; i++)
       putchar(world[i]);
       putchar('\n');
       return 0;
      }

       /* say.c Windows Version */
       __declspec(dllexport) int say(char *hello, char *world)
      {
       int i;
       for (i = 0; i < 6; i++)
       putchar(hello[i]);
       for (i = 0; i < 6; i++)
       putchar(world[i]);
       putchar('\n');
       return 0;
      }

Compile the C program

In Linux/Unix:

>cc -c say.c

In Windows:

>cobc -c say.c

In Linux/Unix:

>cobc -x -o hello hello.o say.o

In Windows:

>cobc -x -o hello hello.obj say.obj

Run the linked executable

In Linux/Unix:

>./hello

In Windows:

>hello

In summary

You can combine the compile and run commands above into scripts (Linux/Unix) or batch files (Windows) as follows:

Linux/Unix:

       >cobc -c -static hello.cbl
       >cc -c say.c
       >cobc -x -o hello hello.o say.o
       >./hello

Windows 32, Windows 64:

       >cobc -c -static hello.cbl
       >cobc -c say.c
       >cobc -x -o hello hello.obj say.obj
       >hello

Running hello returns the following output

       Hello World!

Dynamic linking COBOL programs with C programs

You can call a C shared library from a COBOL-IT program. Begin by compiling your C module(s) into a shared library rather than a static object file, do not use the -static command line option. This will ensure that the COBOL-IT runtime will find the shared library for you.

This sample is also designed to demonstrate a case where C functions are CALL’ed with different parameter types. Note in the example below how say is called using the character strings Hello and World!, and then called again using the integers Val1 and Val2. See say.c for details on how this sort of case is handled within the C program.

The COBOL program

       IDENTIFICATION DIVISION.
       PROGRAM-ID. Hello.
       ENVIRONMENT DIVISION.
       DATA DIVISION.
       WORKING-STORAGE SECTION.
       01 HELLO PIC X(6)   VALUE "Hello ".
       01 WORLD PIC X(6)   VALUE "World!".
       01 VALARE PIC X(9)  VALUE "Value is ".
       01 VAL1 PIC 9(3)    VALUE 10.
       PROCEDURE DIVISION.
       MAIN.
       CALL "say" USING HELLO WORLD.
       CALL "say" USING VALARE VAL1.
       STOP RUN.

Compile the COBOL program

In Linux/Unix, and Windows:

>cobc -x hello.cbl

The C program

       /* say.c */
       #include "libcob.h"
       /* Use function type with COB_CALL_TARGET for been usable from COBOL */
       /* On Windows COB_CALL_TARGET is defined as __declspec(dllexport)*/
       COB_CALL_TARGET int say (char * data1 , char * data2)
      {
           COB_RTD = cob_get_rtd();
           cob_field * f1;
           cob_field * f2;
           int i;
           if (rtd->cob_call_params != 2) {
               printf("Invalid parameter count %d ", rtd->cob_call_params);
               return 0;
           }
           f1 = rtd->current_module->cob_procedure_parameters[0];
           f2 = rtd->current_module->cob_procedure_parameters[1];
           if (COB_FIELD_TYPE(f1) != COB_TYPE_ALPHANUMERIC) {
               printf("Fisrt parameters must be Alphanumeric ");
               return 0;
           }
           for (i = 0; i < f1->size; i++)
               putchar(f1->data[i]);

           switch (COB_FIELD_TYPE(f2)) {
               case COB_TYPE_UNKNOWN:
               case COB_TYPE_GROUP :
       /* COB_FIELD_DATA(f2) point to structure */
                   break;
               case COB_TYPE_ALPHANUMERIC :
               case COB_TYPE_ALPHANUMERIC_ALL:
               case COB_TYPE_ALPHANUMERIC_EDITED :
               case COB_TYPE_NUMERIC_DISPLAY:
               case COB_TYPE_NUMERIC_EDITED :
       /* COB_FIELD_DATA(f2) point to array of char */
                   for (i = 0; i < f2->size; i++)
                       putchar(f2->data[i]);
                   break;
               case COB_TYPE_NUMERIC_BINARY:
       /* COB_FIELD_DATA(f2) point to binary data size of */
       /* f2->size */
       /* if COB_FIELD_BINARY_SWAP(f) is true then bytes */
       /* order are swapped regarding native platform byte order */
                   break;
               case COB_TYPE_NUMERIC_PACKED:
       /* COB_FIELD_DATA(f2) point to COMP-3 data of */
       /* COB_FIELD_DIGITS(f2) digits and COB_FIELD_SCALE(f)
       scale*/
       /* if COB_FIELD_PACKED_SIGN_MISSING(f) is true then field */
       /* is COMP-6*/
                   break;
               case COB_TYPE_NUMERIC_FLOAT :
       /* COB_FIELD_DATA(f2) point to a C float (may be not
       aligned */
                   break;
               case COB_TYPE_NUMERIC_DOUBLE:
       /* COB_FIELD_DATA(f2) point to a C double */
       /* (may be not aligned */
                   break;
               case COB_TYPE_NATIONAL:
               case COB_TYPE_NATIONAL_EDITED:
       /* COB_FIELD_DATA(f2) point to array of UTF16 16bits chars */
                   break;
           }
           putchar('\n');
      }

For more detailed information on cob_field_data, reference libcob/common.h.

Compile the C program

In Linux/Unix:

>cc -shared -o say.so say.c

In Windows:

>cobc -m say.c

In Linux/Unix:

       >export COB_LIBRARY_PATH=.
       >./hello

In Windows:

       >set COB_LIBRARY_PATH=.
       >hello

In summary

You can combine the compile and run commands above into scripts (Linux/Unix) or batch files (Windows) as follows:

Linux/Unix:

       >cobc -x hello.cbl
       >cc -shared -o say.so say.c
       >export COB_LIBRARY_PATH=.
       >./hello

Windows 32, Windows 64:

       >cobc -x hello.cbl
       >cobc -m say.c
       >set COB_LIBRARY_PATH=.
       >hello

Running hello returns the following output

       Hello World!