HP 3000 Manuals

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