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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
To call a Pascal function from C, perform these two tasks:
Write a C extern declaration to describe the return value type of the main routine.
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.
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 | int |
cardinal (also applies to subranges | unsigned int |
char | char |
boolean | char |
enumeration | unsigned, or corresponding enum |
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.)
Table 4-2 shows the C argument types to declare in order to match those expected by the Pascal routine.
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. |
|
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); |
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); |
The following example is a C routine that passes strings to a Pascal procedure, which then prints the strings. The example illustrates two points:
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} |
To call a C routine from Pascal, you must write:
A Pascal declaration describing the C routine.
A procedure declaration or, if the C routine returns a value, a function declaration.
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) |
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); |
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); |
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); |