Calling Other Languages [ HP C Programmer's Guide ] MPE/iX 5.0 Documentation
HP C Programmer's Guide
Calling Other Languages
It is possible to call a routine written in another language from a C
program, but you should have a good reason for doing so. Using more than
one language in a program that you plan to port to another system will
complicate the process. In any case, make sure that the program is
thoroughly tested in any new environment.
If you do call another language from C, you will have the other
language's anomalies to consider plus possible differences in parameter
passing. Since all HP-UX system routines are C programs, calling
programs written in other languages should be an uncommon event. If you
choose to do so, remember that C passes all parameters by value except
arrays and structures. The ramifications of this depend on the language
of the called function.
Table 5-5. C Interfacing Compatibility
----------------------------------------------------------------------------------------------
| | | |
| C | HP-UX Pascal | FORTRAN |
| | | |
----------------------------------------------------------------------------------------------
| | | |
| char | none | byte |
| | | |
| unsigned char | char | character (could reside on an |
| | | odd boundary and cause a memory |
| | | fault) |
| | | |
| char * (string) | none | none |
| | | |
| unsigned char * | PAC+chr(0) (PAC = packed | Array of char+char(0) |
| (string) | array[1..n] of char) | |
| | | |
| short (int) | -32768..32767 (shortint on Series | integer*2 |
| | 700/800) | |
| | | |
| unsigned short | BIT16 on Series 700/800; none on | none |
| (int) | Series 300/400 (0..65535 will | |
| | generate a 16-bit value only if | |
| | in a packed structure) | |
| | | |
| int | integer | integer (*4) |
| | | |
| long (int) | integer | integer (*4) |
| | | |
| unsigned (int) | none | none |
| | | |
| float | real | real (*4) |
| | | |
| double | longreal | real*8 |
| | | |
| long double(1) long | none | real*16 |
| double | | |
| | | |
| type* (pointer) | ^var, pass by reference, or use | none |
| | anyvar | |
| | | |
| &var (address) | addr(var) (requires $SYSPROG$) | none |
| | | |
| *var (deref) | var^ | none |
| | | |
| struct | record (cannot always be done; C | structure |
| | and Pascal use different packing | |
| | algorithms) | |
| | | |
| union | record case of... | union |
| | | |
----------------------------------------------------------------------------------------------
(1) is available only in ANSI mode.
Calling FORTRAN
You can compile FORTRAN functions separately by putting the functions you
want into a file and compiling it with the -c option to produce a .o
file. Then, include the name of this .o file on the cc command line that
compiles your C program. The C program can refer to the FORTRAN
functions by the names they are declared by in the FORTRAN source.
Remember that in FORTRAN, parameters are usually passed by reference
(except CHARACTER parameters on Series 700/800, which are passed by
descriptor), so actual parameters in a call from C must be pointers or
variable names preceded by the address-of operator (&).
The following program uses a FORTRAN block data subprogram to initialize
a common area and a FORTRAN function to access that area:
double precision function get_element(i,j)
double precision array
common /a/array(1000,10)
get_element = array(i,j)
end
block data one
double precision array
common /a/array(1000,10)
C Note how easily large array initialization is done.
data array /1000*1.0,1000*2.0,1000*3.0,1000*4.0,1000*5.0,
* 1000*6.0,1000*7.0,1000*8.0,1000*9.0,1000*10.0/
end
The FORTRAN function and block data subprogram contained in file xx.f are
compiled using f77 -c xx.f.
The C main program is contained in file x.c:
main()
{
int i;
extern double get_element(int *, int *);
for (i=1; i <= 10; i++)
printf("element = %f\n", get_element(&i,&i));
}
The C main program is compiled using cc -Aa x.c xx.o.
Another area for potential problems is passing arrays to FORTRAN
subprograms. An important difference between FORTRAN and C is that
FORTRAN stores arrays in column-major order whereas C stores them in
row-major order (like Pascal).
For example, the following shows sample C code:
int i,j;
int array[10][20];
for (i=0; i<10; i++) {
for (j=0; j<20; j++) /* Here the 2nd dimension
varies most rapidly */
array [i][j]=0;
}
Here is similar code for FORTRAN:
integer array (10,20)
do J=1,20
do I=1,10 !Here the first dimension varies most rapidly
array(I,J)=0
end do
end do
Therefore, when passing arrays from FORTRAN to C, a C procedure should
vary the first array index the fastest. This is shown in the following
example in which a FORTRAN program calls a C procedure:
integer array (10,20)
do j=1,20
do i=1,10
array(i,j)=0
end do
end do
call cproc (array)
.
.
.
cproc (array)
int array [][];
for (j=1; j<20; j++) {
for (i=1; i<20; i++) /* Note that this is the reverse from
how you would normally access the
array in C as shown above */
array [i][j]= ...
}
.
.
.
There are other considerations as well when passing arrays to FORTRAN
subprograms.
It should be noted that a FORTRAN main should not be linked with cc.
Calling Pascal
Pascal gives you the choice of passing parameters by value or by
reference (var parameters). C passes all parameters (other than arrays
and structures) by value, but allows passing pointers to simulate pass by
reference. If the Pascal function does not use var parameters, then you
may pass values just as you would to a C function. Actual parameters in
the call from the C program corresponding to formal var parameters in the
definition of the Pascal function should be pointers.
Arrays correlate fairly well between C and Pascal because elements of a
multidimensional array are stored in row-major order in both languages.
That is, elements are stored by rows; the rightmost subscript varies
fastest as elements are accessed in storage order.
Note that C has no special type for boolean or logical expressions.
Instead, any integer can be used with a zero value representing false,
and non-zero representing true. Also, C performs all integer math in
full precision (32-bit); the result is then truncated to the appropriate
destination size.
The basic method for calling Pascal functions on the Series 300/400 is to
put the Pascal function into a module that exports the function, compile
that file using pc -c, and then link it with your main C program by
including the name of the Pascal .o file on the cc command line.
To call Pascal procedures from C on the Series 700/800, a program may
first have to call the Pascal procedure U_INIT_TRAPS. See the HP Pascal
Programmer's Guide for details about the TRY/RECOVER mechanism.
As true of FORTRAN mains, a Pascal main should not be linked with cc.
To call Pascal procedures from C or FORTRAN on the Series 300/400, the
user must first call the procedure asm_initproc to initialize the heap,
initialize the escape (TRY/RECOVER) mechanism, and set up the standard
files input, output, and stderr. At the end, a call to asm_wrapup should
be made. To work correctly, asm_initproc must be called with the value 0
or 1 (0 = buffered input; 1 = unbuffered input) as a parameter by
reference (i.e., a pointer to 0). Without this parameter, asm_initproc
generates a memory fault. An example is shown below.
The Series 300/400 C program shown below calls two Pascal integer
functions:
main() /* The C main program */
{
int noe = 1;
int *c, *a_cfunc(), *a_dfunc();
int *noecho = &noe;
asm_initproc(noecho); /* Pascal initialization */
c = a_cfunc();
printf("%d\n",c);
c = a_dfunc();
printf("%d\n",c);
asm_wrapup(); /* Pascal closure */
}
The following source is the Pascal module:
module a;
export
function cfunc : integer;
function dfunc : integer;
implement
function cfunc : integer;
var x : integer;
begin
x := MAXINT;
cfunc := x;
end;
function dfunc : integer;
var x : integer;
begin
x := MININT;
dfunc := x;
end;
end.
The command line for producing the Pascal relocatable object is
$ pc -c pfunc.p
On Series 300/400, the command line for compiling the C main program and
linking the Pascal module is
$ cc x.c pfunc.o -lpc
or, on Series 700/800, it is
$ cc x.c pfunc.o -lcl
The following output results:
2147483647
on Series 300/400 and
2147483647
-2147483648
on Series 700/800.
MPE/iX 5.0 Documentation