Chapter 4. Pascal/C Interface
Prev |  | Next

## Chapter 4. Pascal/C Interface

This chapter describes the coding interface between Pascal and C. The Fortran 77 Programmer's Guide describes the Pascal/Fortran interface.

Section 4.1, “Guidelines for Using the Interface,” makes some comparisons between Pascal and C, and lists guidelines for dealing with the differences noted.

Section 4.2, “Calling Pascal from C,” lists rules and examples for calling Pascal from C.

Section 4.3, “Calling C from Pascal,” lists rules and examples for calling C from Pascal.

## Guidelines for Using the Interface

In general, calling C from Pascal and Pascal from C is fairly simple. Most data types in one language have natural counterparts in the other.

Differences exist in eight areas. Section 4.1.1 through Section 4.1.10 describe these differences with some guidelines.

### Single-precision Floating Point

In function calls, C automatically converts single-precision floating point values to double-precision. Pascal passes single-precision floating by-value arguments directly.

Follow these guidelines for passing double-precision values between a C routine and a Pascal routine:

- If possible, write the Pascal routine so that it receives and returns double-precision values.

- If the Pascal routine cannot receive a double-precision value, write a Pascal routine to accept double-precision values from C. Then have that routine call the single-precision Pascal routine.

The compiler has no problem passing single-precision values by reference between C and Pascal.

### Procedure and Function Parameters

C function variables and parameters consist of a single pointer to machine code.

Pascal procedure and function parameters consist of a pointer to the machine code, and a pointer to the stack frame of the lexical parent of the function.

Such values can be declared as structures in C. To create such a structure, put the C function pointer in the first word and 0 in the second. C functions cannot be nested, and have no lexical parent; therefore, the second word is irrelevant.

You cannot call a C routine with a function parameter from Pascal.

### Pascal By-Value Arrays

C never passes arrays by value. In C, an array is actually a sort of pointer, and so passing an array actually passes its address, which corresponds to Pascal by-reference (VAR) array passing.

In practice, this is not a serious problem because passing Pascal arrays by value is not efficient, and so most Pascal array parameters are VAR anyway. When it is necessary to call a Pascal routine with a by-value array parameter from C, pass a C structure containing the corresponding array declaration.

Check your copy of the Pascal Release Notes for detailed instructions to pass packed array integer subranges by value.

### File Variables

The Pascal text type and the C `stdio` package `FILE*` are compatible. However, Pascal passes file variables only by reference. A Pascal routine cannot pass a file variable by value to a C routine. C routines that pass files to Pascal routines should pass the address of the `FILE*` variable, as with any reference parameter.

### Passing String Data Between C and Pascal

C and Pascal handle strings differently. Pascal defines a string as a packed array of characters, where the lower bound of the array is 1 and the upper bound is an integer greater than 1. C indexes arrays from 0 to max-1. For example, Pascal string parameters are typically declared so that the upper bound is large enough to efficiently handle most processing requirements:

    var s:packed array[1..100] of char

In passing an array, Pascal passes the entire array as specified, padding to the end of the array with spaces. Most C programs treat strings as pointers to a single character and use pointer arithmetic to step through the string. A null character (\0 in C) terminates a string in C.

The following example shows a Pascal routine that calls the C routine `strtol` and passes the string s. Note that the routine ensures that the string terminates with a null character.

    type
       astrindex = 1..20;
       astrindex = packed array [astrindex] of char;
       function atoi(var c: astring): integer; external;
    program ptest(output);
       var
          s: astring;
          i: astrindex;
       begin
       argv(1, s); {This predefined Pascal function is a MIPS extension}
       writeln(output, s);
       {  Guarantee that the string is null-terminated (but might
          bash the last character if the argument is too long).
          "lbound" and "hbound" are MIPS extensions. }
       s[hbound(s)] := chr(0);
       for i := lbound(s) to hbound(s) do
           if s[i] = ' ' then
           begin
              s[i] := chr(0);
              break;
           end;
       writeln (output, atoi(s));
       end.

For more information about `strtol`, see the strtol(3c) man page.

### Graphics Strings

Using Graphics Library routines requires conversion for Pascal format strings. You will need to convert Pascal strings to C formats. The procedure file `/usr/lib/p2cstr.o` will perform this conversion for you. If you compile your program with the `-Zg` option, this conversion will be done automatically.

The compile option `-Zg` will link `p2cstr.o` to perform the conversion. If you do not use the - `Zg` option, you must explicitly link p2cstr.o. See Section 2.1.2, “Pascal Driver Options,” for details.

### Passing Variable Arguments

You can define C functions that take a variable number of arguments (`printf` and its variants are examples). You cannot call such functions from Pascal.

### Passing Pointers

A Pascal routine cannot pass a function pointer to a C routine.

You can pass a C pointer to a function to Pascal as a structure by value. The first word of the structure must contain the function pointer and the second word must contain a zero. Pascal requires this format because it expects an environment specification in the second word.

### Type Checking

Pascal checks certain variables for errors at execution time, whereas C does not. For example, in a Pascal program, when a reference to an array exceeds its bounds, the error is flagged (if run time checks are not suppressed). You can not expect a C program to detect similar errors when you pass data to it from a Pascal program.

### One Main Routine

Only one main routine is allowed per program. You can write the main routine in either Pascal or C. Here are examples of C and Pascal routines:

Pascal:

    program p (output);
    begin
       writeln ("hi!");
    end.

C:

    main() {
       printf("hi!\n");
    }

## Calling Pascal from C

To call a Pascal function from C, perform these two tasks:

1. Write a C `extern` declaration to describe the return value type of the main routine.

2. Write the call itself with the return value type and argument types as required by the Pascal routine.

See Section 4.2.3, “Calling a Pascal Function from C” below, for an example.

### C Return Values

Use Table 4-1 below as a guide to declaring the return value type.

Table 4-1. Declaration of Return Value Types

If Pascal function returns: | Declare C function as:
--- | ---
integer (also applies to subranges with lower bounds < 0) | int
cardinal (also applies to subranges with lower bounds > 0) | unsigned int
char | char
boolean | char
enumeration | unsigned, or corresponding enum (recall that C enums are signed)
real | none
double | double
pointer type | corresponding pointer type
record type | corresponding structure or union type
array type | corresponding array type

To call a Pascal procedure from C, write an `extern` declaration in this form:

    extern void name();

Then call it with actual arguments with appropriate types.

Use Table 4-2 as a guide for values to pass that correspond to the Pascal declarations listed.

C does not permit declaration of formal parameter types, but instead infers them from the types of the actual arguments passed. (See Section 4.2.3 for an example.)

### C to Pascal Arguments

Table 4-2 shows the C argument types to declare in order to match those expected by the Pascal routine.

Table 4-2. C Argument Types

If Pascal expects: | C argument should be:
--- | ---
integer | integer or char value -231..231-1
cardinal | integer or char value 0..232-1
subrange | integer or char value in subrange
char | integer or char (0..255)
boolean | integer or char (0 or 1 only)
enumeration | integer or char (0..N-1)
real | none
double | float or double
procedure | struct {void *p(); int *l}
function | struct {function-type *f(); int *l}
pointer types1 | pointer type, under 0 := lbound(s)
reference parameter | pointer to the appropriate type
record types | structure or union type
by-reference array parameters | corresponding array type
by-reference text | FILE**
by-value array parameters | structure containing the corresponding array
1To pass a pointer to a function in a C-to-Pascal call, you must pass a structure by value. The first word of the structure must contain the function pointer and the second word a zero. Pascal requires this format because it expects an environment specification in the second word. |

### Calling a Pascal Function from C

This example shows a C routine calling a Pascal function.

Pascal:

    function bah (
        var f: text;
        i: integer
        ) double;
    begin
        ...
    end {bah};

C declaration of bah:

    extern double bah();

C call:

    int i; double d;
    FILE *f;
    d = bah(&f, i);

### Calling a Pascal Procedure from C

This example shows a C routine calling a Pascal procedure.

Pascal:

    type
      int_array = array[1..100] of integer;
    procedure humbug (
        var a: int_array;
        n: integer
        ): integer;
      begin
        ...
      end {humbug};

C declaration:

    extern void humbug();

C call:

    int a[100];
    int n;
    humbug(a, n);

### Passing Strings to a Pascal Procedure

The following example is a C routine that passes strings to a Pascal procedure, which then prints the strings. The example illustrates two points:

- The Pascal routine must check for the null [chr(0)] character, which indicates the end of the string passed by the C routine.

- The Pascal routine must not write to `output`, but instead uses the `stdout` file-stream descriptor passed by the C routine.

C routine:

    /* Send the last command-line argument to the Pascal routine */

    #include <stdio.h>
    main(int argc, char **argv)
    {
       FILE *temp = stdout;
       if (argc != 0)
          p_routine(&temp, argv[argc-1]);
    }

Pascal routine:

    { We assume the string passed to us by the C program will not  exceed 100 bytes in length. }
    type
      astring = packed array [1..100] of char;
    procedure p_routine(var f: text; var c: astring);
      var
        i: integer;
      begin
        i := lbound(c);
        { check for null character }
        while (i > hbound(c)) and (c[i] <> chr(0)) do
        begin
          write (f, c[i])  { write to file stream descriptor     passed from C }
          i := i+1;
        end;
        writeln(f);
      end; {p_routine}

## Calling C from Pascal

To call a C routine from Pascal, you must write:

1. A Pascal declaration describing the C routine.

2. A procedure declaration or, if the C routine returns a value, a function declaration.

3. Parameter and return value declarations corresponding to the C parameter types, using Table 4-3 below as a guide.

   Table 4-3. Pascal Parameter Data Types Expected by C

   If C expects: | Pascal parameter should be:
   --- | ---
   int (same as`` `` `signed int, long,` `signed long`, and `signed`) | integer
   unsigned int (same as`` `` `unsigned` and `unsigned long`) | cardinal
   short (same as`` `` `signed short`) | integer (or -32768..32767)
   unsigned short | cardinal (or 0..65535)
   char (same as `unsigned` `` `char)` | char
   signed char | integer (or -128..127)
   float | double
   double | double
   enum type | corresponding enumeration type
   string (char *) | packed character array passed by reference (VAR)
   pointer to function | none
   FILE* | none
   FILE** | text, passed by reference (VAR)
   pointer type | corresponding pointer type or corresponding type passed by reference
   struct or union type | corresponding record type
   array type | corresponding array type passed by reference (VAR)

### Calling a C Procedure

The following example shows code calling a C procedure from Pascal.

| Note: A Pascal routine cannot pass a function pointer to a C routine.

C routine:

    void bah (int i, float f, char *s)
    {
        ...
    }

Pascal declaration:

    procedure bah (
        i: integer;
        f: double;
        var a: packed array[1..100] of char);
    external;

Pascal call:

    str := "abc\0";
    bah(i, 1.0, str);

### Calling a C Function

The following example shows code calling a C function from Pascal.

C routine:

    float humbug(FILE **f, struct scrooge *x)
    {
        …
    }

Pascal declaration:

    type
      scrooge_ptr = ^scrooge;
    function humbug (
        var f: text;
        x: scrooge_ptr
        ): double;
      external;

Pascal call:

    x := humbug(input, sp);

### Passing Arrays

The following example shows code calling a C array from Pascal.

C routine:

    int sum(int a[], unsigned n)
    {
        …
    }

Pascal declaration:

    type
      int_array = array[0..100] of integer;
    function sum (
        var a: int_array;
        n: cardinal
        ): integer;
      external;
    avg := sum(samples, hbound(samples) + 1) /
            (hbound(samples)+1);

Prev | Table of Contents | Next
Chapter 3. Storage Mapping |  | Index