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);