HP C/HP-UX Online Help


Return to the Main HP C Online Help page



Calling Other Languages

Comparing HP C and HP Pascal
Comparing HP C and HP Fortran
Comparing Structured Data Type Declarations

This section describes how to call routines written in other HP languages from HP C programs.

Invoking routines or accessing data defined or declared in another programming language from HP C can be tricky. Here are some common problems:

The topics listed above are described in detail in This section. For additional information, the following manuals have chapters on calling other languages:

Comparing HP C and HP Pascal

The following table summarizes the differences in storage allocation between HP C and HP Pascal. The footnote numbers refer to notes located in a section immediately following the table.
 

Table 34: HP C versus HP Pascal Storage Allocation
HP C Type  HP C Description  Corresponding HP Pascal Type  HP Pascal Description 
char, signed char 1 byte, byte aligned 1 byte, byte aligned; Subrange: -128 .. 127
unsigned char 1 byte, byte aligned char 1 byte, byte aligned; Subrange: 0 .. 255
short 2 bytes, 2-byte aligned shortint Subrange: -32768..32767
unsigned short 2 bytes, 2-byte aligned Subrange: 0 .. 65535
int 4 bytes, 4-byte aligned integer 4 bytes, 4-byte aligned; Subrange: -2147483648 .. 2147483647
unsigned int 4 bytes, 4-byte aligned 4 bytes, 4-byte aligned; Subrange: 0 .. 4294967295
long 4 bytes, 4-byte aligned (8 bytes in LP64) integer Subrange: -2147483648 .. 2147483647
unsigned long 4 bytes, 4-byte aligned (8 bytes in LP64) 4 bytes, 4-byte aligned; Subrange: 0 .. 4294967295
(See Note 1) longint 8 bytes, 4-byte aligned
float 4 bytes, 4-byte aligned real 4 bytes, 4-byte aligned
double 8 bytes, 8-byte aligned longreal 8 bytes, 8-byte aligned
long double 16 bytes, 16-byte aligned
enum 4 bytes, 4-byte aligned enumeration or integer (See Note 2) 1 byte if fewer than 257 elements; 2 bytes if between 257 and 65536; otherwise, 4 bytes. 1, 2, or 4-byte aligned.
char enum 1 byte, 1-byte aligned 1 byte, 1-byte aligned, subrange: -128..127
short enum 2 bytes, 2-byte aligned short int subrange: -32768..32767
int enum 4 bytes, 4-byte aligned integer 4 bytes, 4-byte aligned, subrange: -2,147,483,648..2,147,483,647
long enum 4 bytes, 4-byte aligned integer 4 bytes, 4-byte aligned, subrange: -2,147,483,648..2,147,483,647
array [n] oftype Size is number of elements times element size. Align according to element type. ARRAY [0 .. n-1] OF type (See Note 3) Size is the number of elements times element size. Align according to element type.
array [n] of char [n] bytes, byte aligned PACKED ARRAY [0 .. n-1] OF CHAR or not PACKED (See Note 4) [n] bytes, byte aligned
struct (See Note 5) Pascal string descriptors may be emulated using C structures, see the note for an example. STRING [n] Size 4+[n]+1 bytes, 4-byte aligned.
Pointer to string descriptor structure (See Note 6) Pascal VAR parameters may be emulated using C pointers to string descriptor structures. (See Note 6). STRING
char * Pointer to a null terminated array of characters pointer to character array (See Note 7)
struct Size of elements plus padding, aligned according to largest type record (See Note 8)
union Size of elements plus padding, aligned according to largest type (untagged) variant record (See Note 9) (See Note 8)
signed bit-fields packed record (See Note 10)
unsigned bit-fields packed record (See Note 11)
void Used when calling an HP Pascal procedure (See Note 12)
pointer 4 bytes, 4-byte aligned (8 bytes in LP64) pointer to corresponding type 4 bytes, 4-byte aligned
long pointer 8 bytes, 8-byte aligned $ExtnAddr$ pointer or $ExtnAddr$ VAR parameter 8 bytes, 4-byte aligned
char 1 byte, 1-byte aligned boolean (See Note 13) 1 byte, 1 byte aligned
void function parameter 4 bytes, 4-byte aligned PROCEDUREparameter 4 bytes, 4-byte aligned
function parameter 4 bytes, 4-byte aligned FUNCTIONparameter 4 bytes, 4-byte aligned
struct of 1-bit fields (See Note 14) set
Pascal files may be read by C programs with some effort. (See Note 15) file external record oriented file
pointer to void function procedure
pointer to function function

Notes on HP C and HP Pascal

The longint type in HP Pascal is a 64-bit signed integer. A corresponding HP C type could be any structure or array of 2 words; however, HP C cannot directly operate on such an object.

By default, HP C enumerations are allocated 4 bytes of storage, while HP Pascal enumerations use the following scheme:

If the default enumeration specifier is modified with a char or short type specifier, 1 or 2 bytes of storage are allocated.

This is important if the items are packed. For example, a 25-element enumeration in HP Pascal can use 1 byte and be on a byte boundary, so you must use the HP C type char or a sized enum declaration char enum.

HP C always indexes arrays from zero, while HP Pascal arrays can have lower bounds of any user-defined scalar value. This is only important when passing an array using an index to subscript the array. When passing the subscript between HP C and HP Pascal, you must adjust the subscript accordingly. HP C always passes a pointer to the first element of an array. To pass an array by value, enclose the array in a struct and pass the struct.

HP C char arrays are packed one character per byte, as are HP Pascal arrays (even if PACKED is not used). HP Pascal permits certain string operations with a packed array of char when the lower bound is one.

The HP Pascal type STRING [n] uses a string descriptor that consists of the following: a word containing the current length of the string, n bytes for the characters, and an extra byte allocated by the HP Pascal compiler. Thus, the HP Pascal type STRING[10] corresponds to the following HP C structure:

     typedef struct {
        int cur_len;                   /*  4 bytes  */
        char chars [10];               /* 10 bytes  */
        char extra_byte;               /*  1 byte   */
     } STRING_10;
which is initialized like this:
     STRING_10 this_string = {
        0,                              /* The current length */
        {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, /* The 10 bytes       */
        0                               /* The null byte      */
     };
Both the C structure and the Pascal string are 4-byte aligned.

HP Pascal also has a generic string type in which the maximum length is unknown at compile time. Objects of this type have the same structure as in Note 5 above; the objects are only used as VAR formal parameters.

A variable of this type is a pointer to a character array if the string is null-terminated; HP Pascal will not handle the null byte in any special way. An HP C parameter of type "pointer to char" corresponds to an HP Pascal VAR parameter of type "packed array of char." However, the type definition of that VAR parameter must have the bounds specified.

The size is equal to the size of all members plus any padding needed for the alignment. Refer to Chapter 2, "Storage and Alignment Comparisons," in the HP C/HP-UX Programmer's Guide for detailed information on on alignment. The alignment is that of the member with the strictest alignment requirement.

A union corresponds directly to an untagged HP Pascal variant record. For example, the HP C union:

     typedef union {
        int i;
        float r;
        unsigned char c;
     } UNIONTYPE;
corresponds to:
     TYPE
        UNIONTYPE = RECORD CASE INTEGER OF
           1 : (i : INTEGER);
           2 : (r : REAL);
           3 : (c : CHAR);
     END;
The tagged HP Pascal variant record:
     TYPE
        TAGGED_UNIONTYPE = RECORD CASE tag : INTEGER OF
           1 : (i : INTEGER);
           2 : (r : REAL);
     END;
corresponds to this HP C structure:
     typedef struct {
        int tag;
        union {
           int i;
           float r;
        };
     } TAGGED_UNIONTYPE;
HP Pascal subranges with a negative value as their lower bound have enough bits allocated to contain the upper bound, with an extra bit for the sign. Thus, the HP C structure:
     typedef struct {
        int b1 : 1;
        int b2 : 2;
        int b3 : 3;
        int b4 : 4;
        int b5 : 5;
        int b6 : 6;
        int b7 : 7;
     } BITS;
corresponds to the following untagged HP Pascal record:
     TYPE
        BITS = PACKED RECORD
           b1 : BOOLEAN;
           b2 : -2 ..  1;
           b3 : -4 ..  3;
           b4 : -8 ..  7;
           b5 : -16 .. 15;
           b6 : -32 .. 31;
           b7 : -64 .. 63;
        END;
Unsigned bit-fields map onto HP Pascal packed record fields whose types are the appropriate subranges. For example, the HP C structure:
     typedef struct {
        unsigned int b1 : 1;
        unsigned int b2 : 2;
        unsigned int b3 : 3;
        unsigned int b4 : 4;
        unsigned int b5 : 5;
        unsigned int b6 : 6;
        unsigned int b7 : 7;
     } BITS;
corresponds to this untagged HP Pascal record:
     TYPE
        BITS = PACKED RECORD
           b1 : 0 ..   1;
           b2 : 0 ..   3;
           b3 : 0 ..   7;
           b4 : 0 ..  15;
           b5 : 0 ..  31;
           b6 : 0 ..  63;
           b7 : 0 .. 127;
           END;
The type void, when applied to a function declaration, corresponds to an HP Pascal procedure.

HP Pascal allocates one byte for Boolean variables, and only accesses the rightmost bit to determine its value. HP Pascal uses a 1 to represent true and zero for false; HP C interprets any nonzero value as true and interprets zero as false.

HP Pascal sets are packed arrays of unsigned bits. For example, given the HP Pascal set:

     TYPE
         SET_10 = SET OF 0 .. 9;
     VAR s: SET_10;
the corresponding HP C struct would be:
     typedef struct {
          unsigned int b0 : 1;
          unsigned int b1 : 1;
          unsigned int b2 : 1;
          unsigned int b3 : 1;
          unsigned int b4 : 1;
          unsigned int b5 : 1;
          unsigned int b6 : 1;
          unsigned int b7 : 1;
          unsigned int b8 : 1;
          unsigned int b9 : 1;
     } SET_10;
 
     SET_10 s;
Also, the following operation in HP Pascal:
     s := s + [9];
has the following corresponding HP C code:
     s.b9 = 1;
HP C and HP Pascal file types and I/O operations do not correspond.

Passing Parameters Between HP C and HP Pascal

This section describes additional information on parameter passing. All HP C parameters are passed by value except arrays and functions, which are always passed as pointers. Reference parameters to HP Pascal can be implemented in two ways:
  1. By passing the address of an object by applying the address operator & to the variable
  2. By declaring a variable to be a pointer to such a type, assigning an address to the pointer variable, and passing the pointer.

If an HP Pascal procedure or function has a parameter that is an array by value, it can be called from HP C by passing a struct that contains an array of the corresponding type.

Be careful when passing strings to HP Pascal. If the routine expects a packed array of char, be sure to pass a char array. If the routine expects a user-defined string, pass the structure declared in Note 5 above.

The examples below are HP Pascal and HP C source files that show the parameter passing rules. The HP Pascal file contains 2 subroutines, pass_char_arrays() and pass_a_string(). The HP C file contains the main line routine that calls these two subroutines and displays the results. The HP C program is annotated with the expected results.

The following is the HP Pascal procedure called from HP C:

$subprogram$
program p;
const len = 10;
type
  pac_10  = packed array [1..10] of char;
  string_10 = string [len];
 
  function pass_char_arrays (a: pac_10;
    var b: pac_10;
        c: string_10;
           var d: string_10) : integer;
       var
    i : integer;
    ret_val : integer;
       begin
    ret_val := 0;
           for i := 1 to len - 1 do
           begin
        if ( a[i] <> "a" ) then
     ret_val := 1;
               a[i]    := "z";
               if ( b[i] <> "b" ) then
                   ret_val := 256;
               b[i]    := "y";
       end;
 
       for i := 1 to strlen (c) do
       begin
           if ( c[i] <> "c" ) then
        ret_val := 65536;
           c[i] := "x";
       end;
 
       for i := 1 to strlen (d) do
       begin
           if ( d[i] <> "d" ) then
               ret_val := maxint;
            d[i] := "w";
        end;
 pass_char_arrays := ret_val;
    end;
 
function pass_a_string (var a: string) : integer;
  var
      i       : integer;
      ret_val : integer;
  begin
       ret_val := 0;
       for i := 1 to strlen (a) do
       begin
    if (a[i] <> "x" ) then
        ret_val := maxint;
           a[i] := "q";
        end;
 pass_a_string := ret_val;
    end;
 
begin
end.
The following HP C main program calls the HP Pascal procedure:
#include <stdio.h>
#include <string.h>
static struct string_10 {
   int cur_len;
   char chars[10];
};
/* a Pascal routine */
extern int pass_char_arrays (/* pac10,
                                var pac10,
                                string_10,
                                var string[10] */);
main(void)
{
   static struct string_10 a, b, c, d;
   int ret_val;
   strcpy (a.chars, "aaaaaaaaa");
   strcpy (b.chars, "bbbbbbbbb");
   strcpy (c.chars, "ccccccccc");
   c.cur_len = strlen (c.chars);
   strcpy (d.chars, "ddddddddd");
   d.cur_len = 5;
   ret_val = pass_char_arrays (a.chars, b.chars, &c, &d);
 
   printf ("a: %s\n", a.chars);           /* prints aaaaaaaaa */
   printf ("b: %s\n", b.chars);           /* prints yyyyyyyyy */
   printf ("c: %s\n", c.chars); /* value parm prints xxxxxxxxx */
   printf ("d: %s\n", d.chars);           /* prints wwwwwdddd */
   printf ("return mask: %d\n", ret_val); /* print 0 */
 
   ret_val = pass_a_string (&c);
   printf ("c: %s\n", c.chars);           /* prints qqqqqqqqq */
   printf ("return mask: %d\n", ret_val); /* print 0 */
   return 0;
}
The program produces the following output:
a: aaaaaaaaa
b: yyyyyyyyy
c: xxxxxxxxx
d: wwwwwdddd
return mask: 0
c: qqqqqqqqq
return mask: 0
The routine pass_a_string() expects a generic string (described in Note 6 above), so you must pass an extra argument. The extra argument consists of a value parameter containing the maximum length of the char array.

HP Pascal routines do not maintain a null byte at the end of HP C strings. HP Pascal determines the current length of the string by maintaining the length in a 4-byte integer preceding the character data. When an HP Pascal procedure or function (that takes as a parameter a string by reference) is called, the following code is necessary if the Pascal routine modifies the string:

    pass_a_string (a, temp);  /* From note 2 above */
    a.chars[a.cur_len] = "\0";
In non-ANSI mode, HP C promotes most float (32-bit) arguments to double (64-bit). Therefore, all arithmetic using objects defined as float is actually using double code. Float code is only used when the float objects are stored.

In ANSI mode where function prototypes have been declared with a float parameter, no automatic promotion is performed. If the prototype is within the current scope, floats will not be automatically promoted.

To call an HP Pascal routine that expects an argument of type REAL (32-bits), you may either declare a function prototype in ANSI mode, use the +r command line option in non-ANSI mode to always pass floats as floats, or declare the actual parameter as a struct with a float as its only field, such as:

     typedef struct {float f;} PASCAL_REAL_ARG;
HP Pascal global data can usually only be accessed by HP C if the data is declared at the outermost level. HP Pascal stores the names of the objects in lowercase letters.

For example, the HP Pascal global:

     PROGRAM example;
 
     VAR
        PASCAL_GLOBAL: INTEGER;
 
     BEGIN END.
is accessed by HP C with this declaration:
     extern int pascal_global;
The Pascal compiler directives $GLOBAL$ and $EXTERNAL$ can be used to share global data between HP Pascal and HP C.

The $EXTERNAL$ directive should be used to reference C globals from a Pascal subprogram.

The $GLOBAL$ directive should be used to make Pascal globals visible to other languages such as HP C. It should be used if it is necessary to share globals when calling C functions from a Pascal program.

Linking HP Pascal Routines on HP-UX

When calling HP Pascal routines, you must include the HP Pascal run-time libraries by adding the following option to the cc command line:
-lcl
Additionally, the -lm option may be necessary if the Pascal routines use the Pascal predefined math functions.

For details on linking external libraries, see the -l option of the cc(1) and ld(1) commands in the HP-UX Reference manual.

Comparing HP C and HP Fortran

Table 35: HP C versus HP Fortran Storage shows the differences in storage allocation between HP C and HP Fortran. The notes the table refers to are located after the table in the section called "Notes on HP C and HP Fortran."
 

Table 35: HP C versus HP Fortran Storage 
HP C Type  HP C Description  HP Fortran Type  HP Fortran Description 
char, signed char, char enum 1 byte, byte aligned 1 byte, 1-byte aligned
unsigned char 1 byte, byte aligned CHARACTER*1, BYTE 1 byte, 1-byte aligned
short, short enum 2 bytes, 2-byte aligned INTEGER*2 2 bytes, 2-byte aligned
unsigned short 2 bytes, 2-byte aligned
int, int enum 4 bytes, 4-byte aligned INTEGER*4 or INTEGER 4 bytes, 4-byte aligned
unsigned int 4 bytes, 4-byte aligned
long, long enum 4 bytes, 4-byte aligned (8 bytes in LP64) INTEGER*4 or INTEGER 4 bytes, 4-byte aligned
unsigned long 4 bytes, 4-byte aligned (8 bytes in LP64)
float 4 bytes, 4-byte aligned REAL or REAL*4 4 bytes, 4-byte aligned
double 8 bytes, 8-byte aligned REAL*8 or DOUBLE PRECISION 8 bytes, 8-byte aligned
long double 16 bytes, 16-byte aligned REAL*16 16 bytes, 16-byte aligned
(See Note 1) 8 bytes, 4-byte aligned COMPLEX or COMPLEX*8 8 bytes, 4-byte aligned
(See Note 2) 16 bytes, 8-byte aligned DOUBLE COMPLEX or COMPLEX*16 16 bytes, 8-byte aligned
enum 4 bytes, 4-byte aligned INTEGER*4 or INTEGER 4 bytes, 4-byte aligned
pointer to type long pointer to type Not available
string (char *) CHARACTER*n (See Note 3)
char array CHARACTER*1 array (See Notes 4 &5)
(See Note 5) Hollerith array
arrays Size is number of elements times element size. Aligned according to element type. (See Note 4) Size is number of elements times element size. Aligned according to element type.
struct (See Note 6) STRUCTURE Used to declare Fortran record structures.
union (See Note 6) UNION Used to declare Fortran union types.
short (Used for logical test) 2 bytes, 2-byte aligned LOGICAL*2 (See Note 7) 2 bytes, 2-byte aligned
int (Used for logical test) 4 bytes, 4-byte aligned LOGICAL*4 (See Note 7) 4 bytes, 4-byte aligned
void - Used when calling a SUBROUTINE
function Used when calling a FUNCTION

Notes on HP C and HP Fortran

The following HP C structure is equivalent to the HP Fortran type listed in the table:
     struct complex {
        float real_part;
        float imag_part;
     };
The following HP C structure is equivalent to the HP Fortran type listed in the table:
     struct double_complex {
        double real_part;
        double imag_part;
     };
HP Fortran passes strings as parameters using string descriptors corresponding to the following HP C declarations:
        char *char_string;  /* points to string */
        int len;            /* length of string */
HP C stores arrays in row-major order, whereas HP Fortran stores arrays in column-major order. The lower bound for HP C is always zero; for HP Fortran, the default lower bound is 1.

HP C terminates character strings with a null byte, while HP Fortran does not.

The size is equal to the size of all members plus any padding needed for the alignment. Refer to Chapter 2, "Storage and Alignment Comparisons," in the HP C/HP-UX Programmer's Guide for detailed information on alignment. The alignment is that of the member with the strictest alignment requirement.

HP C and HP Fortran do not share a common definition of true or false. In HP Fortran, logical values are determined by the low-order bit of the high-order byte. If this bit is 1, the logical value is .TRUE., and if the bit is zero, the logical value is .FALSE.. HP C interprets nonzero value as true and interprets zero as false.

Mixing C and Fortran File I/O

A Fortran unit cannot be passed to a C routine to perform I/O on the associated file. Nor can a C file pointer be used by a Fortran routine. However, a file created by a program written in either language can be used by a program of the other language if the file is declared and opened within the latter program. C accesses the file using I/O subroutines and intrinsics. This method of file access can also be used from Fortran instead of Fortran I/O.

Be aware that HP Fortran on HP 9000 workstations and servers using HP-UX uses the unbuffered I/O system calls read and write (described in the HP-UX Reference Manual) for all terminal I/O, magnetic tape I/O, and direct access I/O. It uses the system calls fread and fwrite for all other I/O. This can cause problems in programs that mix C and Fortran I/O. In particular, C programs that use stdio(3S) output procedures such as printf and fwrite and Fortran output statements must flush stdio buffers (by calling the libc function fflush) if they are in use before returning to Fortran output or the I/O may be asynchronous (if the library is using write).

Mixing Fortran direct, terminal, or tape READ statements with stdio fread input results in the Fortran READ commencing from the beginning of the next block after the contents of the buffer, not from the current position of the input cursor in the fread buffer. The same situation in reverse may occur by mixing read with a Fortran sequential disc read. You can avoid these problems by using only the read and write calls in the C program that the Fortran I/O library uses.

Passing Parameters Between HP C and HP Fortran

All parameters in HP Fortran are passed by reference. This means that all arguments in an HP C call to an HP Fortran routine must be pointers. In addition, all parameters in an HP C routine called from HP Fortran must be pointers, unless the HP Fortran code uses the $ALIAS directive to define the parameters as value parameters. Refer to the example called "HP Fortran Nested Structure" later in This section.

Passing string variables of any length must be done by: building and passing a two-parameter descriptor (defined in Note 3 above), initializing the string appropriately, and by passing two arguments. The two arguments are the pointer to the characters and the value of the length word. This is shown below:

     char *chars = "Big Mitt";
     int len;
        .
        .
        .
     len = strlen(chars);
 
     pass_c_string (chars, len);
        .
        .
        .

Linking HP Fortran Routines on HP-UX

When calling HP Fortran routines on an HP-UX system, you have to include the HP Fortran run-time libraries by adding the option:
-lcl
to the cc command line.

For details on linking external libraries, see the -l option of the cc(1) and ld(1) commands in the HP-UX Reference manual.

Comparing Structured Data Type Declarations

This section shows how to declare a nested structure in HP C, HP Pascal, and HP Fortran.

HP C Nested Structure

struct x {
   char y [3];
   short z;
   char w [5];
};
 
struct q {
   char n;
   struct x v [2];
   double u;
   char t;
} a;
 
struct u{
   union {
      int x;
      char y[4];
   } uval;
};
HP Pascal Nested Structure
TYPE
   x = RECORD
       y : PACKED ARRAY [1 .. 3] OF CHAR;
       z : SHORTINT;
       w : PACKED ARRAY [1 .. 5] OF CHAR;
       END;
 
   q = RECORD
       n : CHAR;
       v : PACKED ARRAY [1 .. 2] OF x;
       u : LONGREAL;
       t : CHAR;
       END;
 
   u = RECORD
        CASE
        Boolean OF
          TRUE : (x : INTEGER);
          FALSE: (y : ARRAY[1..4] of CHAR);
       END;
VAR a:q;
HP Fortran Nested Structure
program main
structure /x/
        character*3 y
        integer*2 z
        character*5 w
end structure
 
structure /q/
        character n
        record /x/ v(2)
        real*8 u
        character t
end structure
 
 
structure /u/
        union
                map
                    integer*4 x
                end map
                map
                    character*4 y
                end map
        end union
end structure