The C-Pascal Interface |
6 |
![]() |
The examples in this chapter assume that you are using the ANSI C compiler. To invoke ANSI C:
hostname% pc -c -calign my_pascal.pThe -c option produces an unlinked object file. The -calign option causes pc to use C-like data formats for aggregate objects.
hostname% cc my_pascal.o my_c.c -lpc
When you compile a Pascal main routine that calls C, you don't have to use any special options, but the -calign option is again useful. The C object library, libc, is automatically brought in for every Pascal compilation.
For example:
hostname% cc -c my_c.c
hostname% pc -calign my_c.o my_pascal.p
Pascal Type |
C Type |
Size (bytes) |
Alignment (bytes) |
real |
float |
4 |
4 |
integer |
short int |
2 |
2 |
Precautions with Compatible Types
This section describes the precautions you should take when working with compatible types. The shortreal Type
The Pascal shortreal and C float compatibility works if you pass by reference. See "Value Parameters" on page 116 for examples that show you how to pass by value.
Character Strings
C has several assumptions about strings. All C strings are:
Pascal aggregate types may require alignment and layout adjustment to match C unions, structures, and arrays. Pascal aggregate types can be any of the following: arrays, varying arrays, sets, strings, alphas, records, or variant records.
However, you can use the -calign option to eliminate some of these differences. With -calign, the following assumptions are made:
C enumerated types are allocated a full word and can take on arbitrary integer values.
ceiling( ord( highest_element ) / 16 ) |
Direct access to individual elements of a set is highly machine-dependent and should be avoided.
General Parameter Passing in C and Pascal
A few general rules apply to parameter passing:
The Pascal procedure, Samp, in the file Samp.p. Note the procedure definition.
|
procedure Samp(var i: integer; var r: real); begin i := 9; r := 9.9 end; { Samp } |
The commands to compile and execute Samp.p and SampMain.c
|
hostname% pc -c Samp.p hostname% cc Samp.o SampMain.c hostname% a.out 9 9.9 |
Variable Parameters
Pascal passes all variable parameters by reference, which C can do, too. Simple Types without -xl
Without -xl, simple types match, as in the following example:
The commands to compile and execute SimVar.p and SimVarMain.c
|
hostname% pc -c SimVar.p hostname% cc SimVar.o SimVarMain.c hostname% a.out 00000001 00000000 z 9 9 9.9 9.9 |
Simple Types with -xl
With the -xl option, the Pascal real must be paired with a C float, and the Pascal integer must be paired with a C short int. Strings of Characters
The C counterpart to the Pascal alfa and string types are arrays; C passes all arrays by reference. The C counterpart to the Pascal varying is a structure; C passes structures by value.
Fixed Arrays
For a fixed array parameter, pass the same type and size by reference, as shown in the following example:
The C main program, FixVecMain.c
|
#include <stdio.h> extern void FixVec(int [], int *); int main(void) int Sum; FixVec(a, &Sum); } |
The commands to compile and execute FixVec.p and FixVecMain.c
|
hostname% pc -c -calign FixVec.p hostname% cc FixVec.o FixVecMain.c -lpc hostname% a.out 36 |
Although it does not apply in this example, arrays of aggregates in Pascal have, by default, a size that is always a multiple of four bytes. When you use the -calign option to compile the Pascal code, that difference with C is eliminated.
-calign.
The Pascal procedure, DaysOfWeek.p
|
type TDay= array [0..8] of char; TWeek = array [0..6] of day; TYear = array [0..51] of week; procedure DaysOfWeek(var Y: TYear); begin v[1][1] := 'Sunday'; end; |
The C main program, DaysOfWeekMain.c
|
#include <stdio.h> extern void DaysOfWeek(char [][7][9]); int main(void) char Year[52][7][9]; DaysOfWeek(Year); |
The commands to compile and execute DaysOfWeek.p and DaysOfWeekMain.c without -calign
|
hostname% pc -c DaysOfWeek.p hostname% cc DaysOfWeek.o DaysOfWeekMain.c -lpc hostname% a.out Day = '' |
The commands to compile and execute DaysOfWeek.p and DaysOfWeekMain.c with -calign
|
hostname% pc -c -calign DaysOfWeek.p hostname% cc DaysOfWeek.o DaysOfWeekMain.c -lpc hostname% a.out day = 'Sunday ' |
The univ Arrays
You can pass any size array to a Pascal procedure expecting a univ array, although there is no special gain in doing so, because there is no type or size checking for separate compilations. However, if you want to use an existing Pascal procedure that has a univ array, you can do so. All univ arrays that are in, out, in out, or var parameters pass by reference.
The commands to compile and execute UniVec.p and UniVecMain.c with -calign
|
hostname% pc -c -calign UniVec.p hostname% cc UniVec.o UniVecMain.c -lpc hostname% a.out 24 |
Conformant Arrays
For single-dimension conformant arrays, pass upper and lower bounds, placed after the declared parameter list. If the array is multidimensional, pass element widths as well, one element width for each dimension, except the last one.
function ip(var x: array [lb..ub: integer] of real): real; extern double ip(double [], int, int); double v1[10]; |
One bounds pair may apply to several arrays if they are declared in the same parameter group:
function ip(var x,y:array[lb..ub:integer] of real):real; ... double v1[10], v2[10] ; extern double ip() ; double z ; z = ip ( v1, v2, 0, 9 ) ; ... |
With multidimensional arrays, for all dimensions but the last one, pass the low bound, high bound, and element width.
Example 1: Single-Dimension Array
The Pascal procedure, IntCA.p. Pascal passes the bounds pair.
|
procedure IntCA(var a: array [lb..ub: integer] of integer); begin a[1] := 1; a[2] := 2 end; { IntCA } |
The commands to compile and execute IntCA.p and IntCAMain.c with -calign
|
hostname% pc -c -calign IntCA.p hostname% cc IntCA.o IntCAMain.c -lpc hostname% a.out 0 1 2 |
Example 2: Multi-Dimension Array
The commands to compile and execute RealCA.p and RealCAMain.c with -calign
|
hostname% pc -c -calign RealCA.p hostname% cc RealCA.o RealCAMain.c -lpc hostname% a.out 1.0 0.0 0.0 0.0 1.0 0.0 |
If wc is the width of the smallest element, as determined by sizeof(), then the width of the next largest element is the number of those smaller elements in the next larger element multiplied by wc.
width of next largest element = (ub - lb + 1) * wc
In general, (lb, ub, wc) are the bounds and element width of the next lower dimension of the array. This definition is recursive. Example 3: Array of Characters
The Pascal procedure, ChrCAVar.p
|
procedure ChrCAVar(var a: array [lb..ub: integer] of char); begin a[0] := 'T'; a[13] := 'o'; end; { ChrCAVar } |
The commands to compile and execute ChrCAVar.p and ChrCAVarMain.c
|
hostname% pc -c -calign ChrCAVar.p hostname% cc ChrCAVar.o ChrCAVarMain.c -lpc hostname% a.out This is a string |
Records and Structures
In most cases, a Pascal record describes the same objects as its C structure equivalent, provided that the components have compatible types and are declared in the same order. The compatibility of the types depends mostly on size and alignment. For more information on size and alignments of simple components, see "Compatibility of Types for C and Pascal" on page 94.
By default, the alignment of a record is always four bytes and the size of a record is always a multiple of four bytes. However, when you use -calign in compiling the Pascal code, the size and alignment of the Pascal record matches the size and alignment of the equivalent C structure.
The commands to compile and execute StruChr.p and StruChrMain.c
|
hostname% pc -c StruChr.p hostname% cc StruChr.o StruChrMain.c -lpc hostname% a.out s25='St. Petersburg' strlen(s25) = 13 |
The record in the example above has, by default, the same size and alignment as the equivalent C record. Some records, though, are laid out differently unless you use the -calign option.
When you compile the Pascal routine without using the -calign option, the program does not work correctly.
Variant Records
C equivalents of variant records can sometimes be constructed, although there is some variation with architecture and sometimes a need to adjust alignment. You can avoid the need to adjust alignment by using the -calign option.
The commands to compile and execute VarRec.p and VarRecMain.c
|
hostname% pc -c -calign VarRec.p hostname% cc VarRec.o VarRecMain.c -lpc hostname% a.out Z |
Pascal Set Type
In Pascal, a set type is implemented as a bit vector, which is similar to a C short-word array. Direct access to individual elements of a set is highly machine-dependent and should be avoided.
Set |
Bit Numbering |
set+3: |
31, 30, 29, 28, 27, 26, 25, 24 |
set+2: |
23, 22, 21, 20, 19, 18, 17, 16 |
set+1: |
15, 14, 13, 12, 11, 10, 9, 8 |
set+0: |
7, 6, 5, 4, 3, 2, 1, 0 |
In C, a set could be described as a short-word array beginning at an even address. With the current set representation, it does not matter what the lower-bound value is.
Pascal intset Type
The Pascal intset type is predefined as set of [0..127]. A variable of this type takes 16 bytes of storage.
The Pascal procedure, IntSetVar.p, which has an intset of the elements [1, 3, 7, 8]
|
procedure IntSetVar(var s: intset); begin s := [1, 3, 7, 8] end; { IntSetVar } |
Value Parameters
There are three types of value parameters in Pascal. Simple Types without -xl
Without -xl, simple types match, as in the following example:
The commands to compile and execute SimVal.p and SimValMain.c
|
hostname% pc -c SimVal.p hostname% cc SimVal.o SimValMain.c -lpc hostname% a.out args=111111 |
If no function prototype is provided for SimVal in SimValMain.c, then sr:shortreal must be changed to sr:real in SimVal.p. This change is necessary because in C, a float is promoted to double in the absence of function prototypes. In -xl mode, change sr:shortreal to sr:longreal.
Simple Types with -xl
With -xl, the Pascal real must be paired with a C float, and the Pascal integer must be paired with a C short int. Arrays
Since C cannot pass arrays by value, it cannot pass strings of characters, fixed arrays, or univ arrays by value. Conformant Arrays
Pascal passes all value parameters on the stack or in registers, except for value conformant array parameters, which are handled by creating a copy in the caller environment and passing a pointer to the copy. In addition, the bounds of the array must be passed (see "Conformant Arrays" on page 105).
This example is the same as the single-dimension example in "Conformant Arrays," except that the var prefix is deleted.
The Pascal procedure, ChrCAVal.p
|
procedure ChrCAVal(a: array [lb..ub: integer] of char); begin a[0] := 'T'; a[13] := 'o'; end; { ChrCAVal } |
The commands to compile and execute ChrCAVal.p and ChrCAValMain.c with -calign
|
hostname% pc -c -calign ChrCAVal.p hostname% cc ChrCAVal.o ChrCAValMain.c -lpc hostname% a.out This is a string |
Function Return Values
Function return values match types the same as with parameters, and they pass in much the same way. Simple Types
The simple types pass in a straightforward way, as follows:
The Pascal function, RetReal.p
|
function RetReal(x: real): real; begin RetReal := x + 1.0 end; { RetReal } |
The C main program, RetRealMain.c
|
#include <stdio.h> extern double RetReal(double); int main(void) r = 2.0; |
The commands to compile and execute RetReal.p and RetRealMain.c
|
hostname% pc -c RetReal.p hostname% cc RetReal.o RetRealMain.c hostname% a.out 3.000000 |
Input and Output
If your C main program calls a Pascal procedure that does I/O, then include the following code before you call the Pascal procedure:
PASCAL_IO_INIT(); |
Also, in the C main program just before exit, add the following line:
PASCAL_IO_DONE(); |
Procedure Calls: Pascal-C
This section parallels the section, "Procedure Calls: C-Pascal" on page 97. Earlier comments and restrictions also apply here.
Variable Parameters
Pascal passes all variable parameters by reference, which C can do, too. Simple Types
Simple types pass in a straightforward manner, as follows:
The C function, SimRef.c
|
void SimRef( { *t = 1; |
The commands to compile and execute SimRef.c and SimRefMain.p
|
hostname% cc -c SimRef.c hostname% pc SimRef.o SimRefMain.p hostname% a.out true false z 9 9 9.9 9.9 |
Strings of Characters
The alfa and string types pass simply; varying strings are more complicated. All pass by reference.
The commands to compile and execute StrVar.c and StrVarMain.p
|
hostname% cc -c StrVar.c hostname% pc StrVar.o StrVarMain.p hostname% a.out abcdefghij abcdefghijklmnopqrtstuvwxyz varstr length(v) = 6 |
Avoid constructs that rely on strings being in static variable storage. For example, you could use mktemp(3) in Pascal as follows:
Incorrect use of string in static variable storage
|
tmp := mktemp('/tmp/eph.xxxxxx') |
This use is incorrect, since mktemp()modifies its argument. Instead, use the C library routine strncpy() (see string(3)) to copy the string constant to a declared char array variable, as in:
Fixed Arrays
For a fixed-array parameter, pass the same type and size, as in this example:
The C function, FixVec.c
|
void FixVec(int V[9], int *Sum) { int i; *Sum = 0; |
The commands to compile and execute FixVec.c and FixVecMain.p
|
hostname% cc -c FixVec.c hostname% pc -calign FixVec.o FixVecMain.p hostname% a.out 36 |
The -calign option is not needed for this example, but may be necessary if the array parameter is an array of aggregates.
The univ Arrays
The univ arrays that are in, out, in out, or var parameters pass by reference.
The C function, UniVec.c
|
void UniVec(int V[3], int Last, int *Sum) *Sum = 0; |
The commands to compile and execute UniVec.c and UniVecMain.p
|
hostname% cc -c UniVec.c hostname% pc -calign UniVec.o UniVecMain.p hostname% a.out 24 |
The -calign option is not needed for this example, but may be necessary if the array parameter is an array of aggregates.
Conformant Arrays
For single-dimension conformant arrays, pass upper and lower bounds placed after the declared parameter list. If the array is multidimensional, pass element widths as well, one element width for each dimension, except the last one. Chapter 8, "The FORTRAN-Pascal Interface," has an example of multidimensional conformant array passing.
The following example uses a single-dimension array:
The C function, IntCA.c
|
void IntCA(int a[], int lb, int ub) int k; for (k=0; k <= ub - lb; k++) |
The commands to compile and execute IntCA.c and IntCAMain.p
|
hostname% cc -c IntCA.c hostname% pc -calign IntCA.o IntCAMain.p hostname% a.out 4 4 4 |
The -calign option is not needed for this example, but may be necessary if the array parameter is an array of aggregates.
Records and Structures
In most cases, a Pascal record describes the same objects as its C structure equivalent, provided that the components have compatible types and are declared in the same order. For more information, see "Compatibility of Types for C and Pascal" on page 94.
Records that contain aggregates may differ because aggregates in C and Pascal sometimes have different sizes and alignments. If you compile the Pascal code with the -calign option, the differences are eliminated.
The C function, StruChr.c
|
#include <string.h> struct TVarLenStr { void StruChr(struct TVarLenStr *v) strncpy(v->a, "strvar", 6); |
The commands to compile and execute StruChr.c and StruChrMain.p
|
hostname% cc -c StruChr.c hostname% pc -calign StruChr.o StruChrMain.p hostname% a.out string=' strvar' length= 6 |
Variant Records
C equivalents of variant records can sometimes be constructed, although there is some variation with the architecture, and sometimes you have to adjust the alignment.
The commands to compile and execute VarRec.c and VarRecMain.p
|
hostname% cc -c VarRec.c hostname% pc -calign VarRec.o VarRecMain.p hostname% a.out Z |
The -calign option is not needed in the previous example, but may be necessary if the record contains aggregates.
Non-Pascal Procedures
When you use the -xl option in compiling Pascal code, you can use the nonpascal keyword to declare that an external procedure is written in another language. This keyword generally causes everything to be passed by reference.
The commands to compile and execute NonPas.c and NonPasMain.p
|
hostname% cc -c NonPas.c hostname% pc NonPas.o NonPasMain.p hostname% a.out Hello from Pascal Hello from Pascal |
Value Parameters
In general, Pascal passes value parameters in registers or on the stack, widening to a full word if necessary. Simple Types
With value parameters, simple types match, as in the following example:
The commands to compile and execute SimVal.c and SimValMain.p
|
hostname% cc -c SimVal.c hostname% pc SimVal.o SimValMain.p hostname% a.out args=111111 |
Function Return Values
Function return values match types in the same manner as with parameters, and they pass in much the same way. See "Variable Parameters" on page 98. The following example shows how to pass simple types.
The C function, RetReal.c
|
double RetReal(double *x) |
The commands to compile and execute RetReal.c and RetRealMain.p
|
hostname% cc -c RetReal.c hostname% pc RetReal.o RetRealMain.p hostname% a.out 2.0 3.0 |
Parameters That Are Pointers to Procedures
Pascal has a special type that is a pointer to a procedure. A variable of this type can be used as a parameter, as follows:
The C function, ProcPar.c
|
#include <string.h> void proc_c (void (*p)()) /* a pointer to procedure argument */ { char *s ; s = "Called from C"; (*p)( s, strlen(s)); /* Call the Pascal routine */ } |
The commands to compile and execute ProcPar.c and ProcParMain.p
|
hostname% cc -c ProcPar.c hostname% pc ProcPar.o ProcParMain.p hostname% a.out Hello from PROC_PASCAL: Called from C |
Procedures and Functions as Parameters
It is probably clearer to pass a pointer to a procedure than to pass the procedure name itself. See "Procedure Calls: Pascal-C" on page 121.
A procedure or function passed as an argument is associated with a static link to its lexical parent's activation record. When an outer block procedure or function is passed as an argument, Pascal passes a null pointer in the position normally occupied by the passed routine's static link. So that procedures and functions can be passed to other languages as arguments, the static links for all procedure or function arguments are placed after the end of the conformant array bounds pairs, if any.
Global Variables in C and Pascal
If the types are compatible, a global variable can be shared between C and Pascal.
The Pascal procedure, GloVar.p
|
var Year: integer; procedure GloVar; begin Year := 2001 end; { GloVar } |
The C main program, GloVarMain.c
|
#include <stdio.h> extern void GloVar(); int Year; int main(void) { Year = 2042; GloVar(); printf( " %d \n", Year ) ; } |
File-Passing Between Pascal and C
You can pass a file pointer from Pascal to C, then have C do the I/O, as in: