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
Statically link the COBOL and C programs
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
Dynamically link the COBOL and C programs
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!