Previous Next Contents Index Doc Set Home


The C++-Pascal Interface

7


This chapter describes how to mix C++ and Pascal modules in the same program. It contains the following sections:

Sample Interface

page 141

Compatibility of Types for C++ and Pascal

page 142

C++ Name Encoding

page 142

Procedure Calls: C++-Pascal

page 142

Procedure Calls: Pascal-C++

page 158

Global Variables in C++ and Pascal

page 164

Pascal File Pointers to C++

page 165


Sample Interface

You must use the compiler option -lpc when you use CC to link a C++ main routine that calls Pascal. -lpc denotes linking with the Pascal runtime support library libpc. On the Solaris 1.x environment, if you use pc to link, you must add the -lc option.

The -calign option causes pc to use data formats for aggregate objects similar to those in C++.


Compatibility of Types for C++ and Pascal

Table 6-1 and Table 6-2 on page 94 list the default sizes and alignments of compatible types for C and Pascal. They apply to C++ as well.


C++ Name Encoding

To implement function overloading and type-safe linkage, the C++ compiler normally appends type information to the function names. To prevent the C++ compiler from doing so, and to allow Pascal to call a C++ function, declare the C++ function with the extern "C" language construct. One common way to do this is in the declaration of a function, like this:

extern "C" void f (int);
...
void f (int) { /* ...body of f... */ }

For brevity, you can also combine extern "C" with the definition of the function, as in:

extern "C" void f (int)
{ /* ...body of f... */ }


Procedure Calls: C++-Pascal

Following are examples that illustrate how a C++ main program calls a Pascal procedure. Included in each example are the Pascal procedure, the C++ main program, and the commands to compile and execute the final program.

The Pascal procedure, Samp, in the file, Samp.p

procedure Samp (var i: integer; var r: real);

begin
i := 7;
r := 3.14;
end

The C++ main program, SampMain.cc

#include <stdio.h>

extern "C" void Samp (int&, double&);
int main(void)
{
int i;
double d;
Samp (i, d);
printf ("%d %3.2f \n", i, d);
}

The commands to compile and execute Samp.p and
SampMain.cc

hostname% pc -c Samp.p
hostname% CC Samp.o SampMain.cc -lpc
hostname% a.out
7 3.14

Arguments Passed by Reference

C++ arguments can be passed by reference. This section describes how they work with Pascal.

Simple Types without the -xl Option

Without the -xl option, simple types match, as in the following example:

The Pascal procedure, SampRef, in the file, Samp.p

procedure SamRef (
var t, f: boolean;
var c: char;
var i: integer;
var s: integer16;
var r: shortreal;
var d: real
);

begin
t := true;
f := false;
c := 'z';
i := 9;
s := 9;
r := 9.9;
d := 9.9;
end;

The C++ main program,
SamRefMain.cc

#include <stdio.h>

extern "C" void SamRef (
char &,
char &,
char &,
int &,
short &,

float &,
double &);

int main(void)
{
char t, f, c;
int i;
short s;

float r;
double d;

SamRef (t, f, c, i, s, r, d);
printf ("%08o %08o %c %d %d %3.1f %3.1f \n",
t, f, c, i, s, r, d);

}

The commands to compile and execute SamRef.p and
SamRefMain.cc

hostname% pc -c SamRef.p
hostname% CC SimRef.o SamRefMain.cc -lpc
hostname% a.out
00000001 00000000 z 9 9 9.9 9.9

Simple Types with the -xl Option

With the -xl option, the Pascal real must be paired with a C++ float; 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. The C++ counterpart to the Pascal varying type is a structure.

Here is an example:

The Pascal procedure, StrRef.p

type
TVarStr = varying [25] of char;

procedure StrRef (
var a: alfa;
var s: string;
var v: TVarStr
);

begin
a := 'abcdefghi' + chr(0);
s := 'abcdefghijklmnopqrstuvwxyz' + chr(0);
v := 'varstr' + chr(0);
end;

The C++ main program, StrRefMain.cc

#include <stdio.h>
#include <string.h>

struct TVarLenStr {
int NBytes;
char a[25];
};

extern "C" void StrRef (
char *,
char *,
TVarLenStr &);

int main(void)
{
struct TVarLenStr vls;
char s10[10],
s80[80],
s25[25];

vls.NBytes = 0;
StrRef (s10, s80, vls);
strncpy (s25, vls.a, vls.NBytes);
printf (" s10 = '%s' \n s80 = '%s' \n s25 = '%s' \n",
s10, s80, s25);
printf (" strlen (s25) = %d \n", strlen(s25));

}

The commands to compile and execute StrRef.p and StrRefMain.cc

hostname% pc -c StrRef.p
hostname% CC StrRef.o StrRefMain.cc -lpc
hostname% a.out
s10 = 'abcdefghi'
s80 = 'abcdefghijklmnopqrstuvwxyz'
s25 = 'varstr'
strlen (s25) = 6

Fixed Arrays

The Pascal procedure, FixVec.p

type
TVec = array [0..8] of integer;

procedure FixVec (
var V: TVec;
var Sum: integer
);
var
i: integer;

begin
Sum := 0;
for i := 0 to 8 do
Sum := Sum + V[i];
end;

The C++ main program, FixVedMain.cc

#include <stdio.h>

extern "C" void FixVec (
int [],
int &);

int main(void)
{
int Sum;
static int a[] = {1,2,3,4,5,6,7,8,9};

FixVec (a, Sum);

printf (" %d \n", Sum);
}

The commands to compile and execute FixVec.p and
FixVecMain.cc

hostname% pc -c FixVec.p
hostname% CC FixVec.o FixVecMain.cc -lpc
hostname% a.out
45

Although it does not apply to this example, arrays of aggregates in Pascal have, by default, a size that is a multiple of four bytes. When you use the -calign option to compile Pascal code, that difference from C++ is eliminated.

The following example illustrates this point. The string 'Sunday' gets through to the C++ main program only when you compile the Pascal routine using the -calign option.

The Pascal procedure, DaysOfWeek.p

type
TDay = array [0..8] of char;
TWeek = array [0..6] of TDay;
TYear = array [0..51] of TWeek;

procedure DaysOfWeek (
var Y: TYear
);

begin
Y[1][1] := 'Sunday';
end;

The C++ main program, DaysOfWeekMain.cc

#include <stdio.h>

extern "C" void DaysOfWeek (
char [52][7][9]);

int main(void)
{
char Year [52][7][9];

DaysOfWeek (Year);

printf (" Day = '%s' \n", Year[1][1]);
}

The commands to compile and execute DaysOfWeek.p and
DaysOfWeekMain.cc without the -calign option

hostname% pc -c DaysOfWeek.p
hostname% CC DaysOfWeek.o DaysOfWeekMain.cc -lpc
hostname% a.out
Day = ''

The commands to compile and execute DaysOfWeek.p and
DaysOfWeekMain.cc with the -calign option

hostname% pc -c -calign DaysOfWeek.p
hostname% CC DaysOfWeek.o DaysOfWeekMain.cc -lpc
hostname% a.out
Day = 'Sunday'

Records and Structures

A Pascal record of an integer and a character string matches a C++ structure of the same constructs, as in this example:

The Pascal procedure, StruChr.p. It is safer for the Pascal procedure to explicitly provide the null byte and include it in the count before the string is passed to C++.

type
TLenStr = record
NBytes: integer;
ChrStr: array [0..24] of char;
end;

procedure StruChr (
var v: TLenStr
);

begin
v.NBytes := 14;
v.ChrStr := 'St.Petersburg' + chr(0);
end;

The C++ main program, StruChrMain.cc

#include <stdio.h>
#include <string.h>

struct TVarLenStr {
int NBytes;
char a[25];
};

extern "C" void StruChr (
TVarLenStr &);

int main(void)
{
struct TVarLenStr vls;
char s25[25];

vls.NBytes = 0;
StruChr (vls);
strncpy (s25, vls.a, vls.NBytes);
printf ("s25 = '%s' \n", s25);
printf ("strlen (s25) = %d \n", strlen(s25));

}

The commands to compile and execute StruChr.p and
StruChr.cc

hostname% pc -c StruChr.p
hostname% CC StruChr.o StruChrMain.cc -lpc
hostname% a.out
s25 = 'St.Petersburg'
strlen (s25) = 13

Consider this example:

The Pascal procedure,
DayWeather.p

type
TDayWeather = record
TDay: array [0..8] of char;
TWeather: array [0..20] of char;
end;
TDayWeatherArray = array [0..1] of TDayWeather;

procedure DayWeather (
var W: TDayWeatherArray;
var WeatherSize: integer
);

begin
W[1].TDay := 'Sunday';
W[1].TWeather := 'Sunny';
WeatherSize := 5;
end;

The C++ main program, DayWeatherMain.cc

#include <stdio.h>
#include <string.h>

struct TDayRec {
char TDay[9];
char TWeather[21];
};

extern "C" void DayWeather (
TDayRec [2],
int &);

int main(void)
{
struct TDayRec dr[2];
int NBytes;
char s25[25];
char t25[25];
NBytes = 0;
DayWeather (dr, NBytes);

strncpy (s25, dr[1].TDay, 6);
printf (" day = '%s' \n", s25);
strncpy (t25, dr[1].TWeather, NBytes);
printf (" weather = '%s' \n", t25);

}

When you compile the Pascal routine without the -calign option, the program does not work correctly.

hostname% pc -c DayWeather.p
hostname% CC DayWeather.o DayWeatherMain.cc -lpc
hostname% a.out
day = ''
weather = ' Sun'

Compile with the -calign option. The program now works correctly.

hostname% pc -calign -c DayWeather.p
hostname% CC DayWeather.o DayWeatherMain.cc -lpc
hostname% a.out
day = 'Sunday'
weather = 'Sunny'

Arguments Passed by Value

C++ arguments can be passed by value. In this section, we describe how they work with Pascal.

Simple Types without the -xl Option

Without the -xl option, simple types match, as in the following example:

The Pascal procedure, SimVal.p

procedure SimVal(
t, f: boolean;
c: char;
si:integer16;
i: integer;
sr:shortreal;
r: real;
var Reply: integer);

begin
Reply := 0;
if t then
Reply := Reply + 1;
if not f then
Reply := Reply + 8
if c='z' then
Reply := Reply + 64;
if si=9 then
Reply := Reply + 512;
if i=9 then
Reply := Reply + 4096;
if sr=shortreal(9.9) then
Reply := Reply + 32768;
if r=9.9 then
Reply := Reply + 262144;

end;

The C++ main program, SimValMain.cc

#include <stdio.h>

extern "C" void SimVal(
char,
char,
char,
short,
int,
float,
double,
int &);
int main(void)
{
char t = 1, f = 0, c= 'z';
short si = 9;
int i=9;
float sr = 9.9;
double r =9.9;
int args;

SimVal (t, f, c, si, i, sr, r, args);
printf (" args = %07o \n", args);
return 0;
}

The commands to compile and execute SimVal.p and
SimVal.cc

hostname% pc -c SimVal.p
hostname% CC SimVal.o SimValMain.cc -lpc
hostname% a.out
args = 111111

Function Return Values

Function return values match types in the same manner as with parameters. They pass in much the same way.

Simple Types

Simple types pass in a straightforward way, as in the following example:

The Pascal function, RetReal.p

function RetReal (r: real): real;

begin
RetReal := r + 1
end;

The C++ main program, RetRealMain.cc

#include <stdio.h>

extern "C" double RetReal (double);

int main(void)
{
double r, s;
r = 2.0;

s = RetReal (r);

printf (" %f \n", s);

}

The commands to compile and execute RetReal.p and
RetRealMain.cc

hostname% pc -c RetReal.p
hostname% CC RetReal.o RetRealMain.cc -lpc
hostname% a.out
3.000000

Type shortreal

The Pascal function, RetShortReal.p

function RetShortReal (r: shortreal): shortreal;

begin
RetShortReal := r + 1.0
end;

The C++ main program, RetShortRealMain.cc

#include <stdio.h>
#include <math.h>

extern "C" float RetShortReal (float);

int main(void)
{
float r, s;
r = 2.0;

s = RetShortReal(r);

printf (" %8.6f \n", s);

}

The commands to compile and execute RetShortReal.p and RetRealMain.cc

hostname% pc -c RetShortReal.p
hostname% CC RetShortReal.o RetShortRealMain.cc -lpc
hostname% a.out
3.000000

Input and Output

The Pascal function, IO.p

procedure IO;

begin
writeln ('Hello, Pascal & St.Petersburg !');
end;

The C++ main program, IOMain.cc

#include <stdio.h>

extern "C" {
void IO ();
};

int main(void)
{
IO ();

printf ("Hello, C++ ! \n");

}

The commands to compile and execute IO.p and IOMain.cc

hostname% pc -c IO.p
hostname% CC IO.o IOMain.cc -lpc
hostname% a.out
Hello, Pascal & St.Petersburg !
Hello, C++ !


Procedure Calls: Pascal-C++

A Pascal main program can also call C++ functions. The following examples show you how to pass simple types and arguments and include the commands that are used to compile and execute the final programs.

Arguments Passed by Reference

Pascal arguments can be passed by reference. Here we discuss how they work with C++.

Simple Types Passed by Reference

Simple types pass in a straightforward manner, as follows:

The C++ function, SimRef.cc

extern "C"
void SimRef (

char &t,
char &f,
char &c,
int &i,
short &s,

float &r,
double &d)
{
t = 1;
f = 0;
c = 'z';
i = 9;
s = 9;

r = 9.9;
d = 9.9;
}

The Pascal main program, SimRefMain.p

program SimRefMain (output);
var
t, f: boolean;
c: char;
i: integer;
s: integer16;

r: shortreal;
d: real;

procedure SimRef (
var t, f: boolean;
var c: char;
var i: integer;
var s: integer16;

var r: shortreal;
var d: real
); external C;

begin
SimRef (t, f, c, i, s, r, d);
writeln (t, f: 6, c: 2, i: 2, s: 2, r: 4: 1, d: 4: 1);
end.

The commands to compile and execute SimRef.cc and SimRefMain.p

hostname% CC -c SimRef.cc
hostname% pc SimRef.o SimRefMain.p
hostname% a.out
true false z 9 9 9.9 9.9

Arguments Passed by Value

Pascal arguments can also be passed by value. Here is how they work with C++.

Simple Types

Simple types match with value parameters. See the following example:

The C++ function, SimVal.cc

extern "C" void SimVal(
  char   t,
  char   f,
  char   c,
  short  si,
  int    i,
  float  sr,
  double r,
  int&   Reply)
{
  Reply = 0;
  if (t)                Reply +=       01;
  if (! f)              Reply +=      010;
  if (c == 'z')         Reply +=     0100;
  if (si == 9)          Reply +=    01000;
  if (i == 9)           Reply +=   010000;
  if (sr == (float)9.9) Reply +=  0100000;
  if (r == 9.9)         Reply += 01000000;
}

The Pascal main program, SimValMain.p

program SimValMain(output);
var
  t: boolean  := true;
  f: boolean  := false;
  c: char     := 'z';
  si:integer16:= 9;
  i: integer  := 9;
  sr:shortreal:= 9.9;
  r: real     := 9.9;
  args: integer;

procedure SimVal(
  t, f: boolean;
  c: char;
  si:integer16;
  i: integer;
  sr:shortreal;
  r: real;
  var Reply: integer); external C;

begin
  SimVal(t, f, c, si, i, sr, r, args);
  writeln(' args = ', args :7 oct);
end.

The commands to compile and execute SimVal.cc and SimValMain.p

hostname% CC -c SimVal.cc
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. They pass in much the same way.

The following example shows how to pass simple types:

The C++ function, RetReal.cc

extern "C"
double RetReal (double &x)
{
return (x + 1.0);
}

The Pascal main program, RetRealMain.p

program RetRealMain (output);
var
r, s: real;

function RetReal (var x: real): real; external C;

begin
r := 2.0;
s := RetReal (r);
writeln ( r: 4: 1,' Return - ', s: 4: 1);
end.

The commands to compile and execute RetReal.cc and RetRealMain.p

hostname% CC -c RetReal.cc
hostname% pc RetReal.o RetRealMain.p
hostname% a.out
2.0 Return - 3.0


Global Variables in C++ and Pascal

If the types are compatible, a global variable can be shared between C++ and Pascal. See this example:

The Pascal procedure, GloVar.p

var
Year: integer;

procedure GloVar;

begin
Year := 1995;
end;

The C++ main program, GloVarMain.cc

#include <stdio.h>

extern "C" void GloVar ();

int Year;

int main(void)
{
Year = 2042;
GloVar ();
printf (" %d \n", Year);
}

The commands to compile and execute GloVar.p and GloVarMain.cc

hostname% pc -c GloVar.p
hostname% CC GloVar.o GloVarMain.cc -lpc
hostname% a.out
1995


Pascal File Pointers to C++

You can pass a file pointer from Pascal to C++, then have C++ do the I/O. See this example.

The C++ procedure, UseFilePtr.cc

#include <stdio.h>

extern "C"
void UseFilePtr (FILE* ptr)
{
fprintf (ptr, "[1] \n");
fprintf (ptr, "[2] \n");
fprintf (ptr, "[3] \n");
}

The C++ main program, UseFilePtrMain.p

program UseFilePtrMain (output);
var
f: text;
cfile: univ_ptr;

procedure UseFilePtr (cf: univ_ptr); external C;

begin
rewrite (f, 'myfile.data');
cfile := getfile (f);
UseFilePtr (cfile);
end.

The commands to compile and execute UseFilePtr.cc and UseFilePtrMain.p

hostname% CC -c UseFilePtr.cc
hostname% pc UseFilePtr.o UseFilePtrMain.p
hostname% a.out
[1]
[2]
[3]


Previous Next Contents Index Doc Set Home