This section provides guidelines for linking HP aC++ modules with modules written in HP C, HP Pascal, and HP FORTRAN 90 on HP 9000 Series 700/800 systems.
Select from the following topics:
When creating an executable file from a group of programs of mixed languages, one of them being C++, you need to be aware of the following:
main() function should appear in a C++ module
and no other outer block should be present.
extern "C" linkage specification to declare any modules
that are not written in C++; this is true whether or not the module is
written in C.
NOTE:
Do not use extern "C" when including standard C header files
because these header files already contain extern "C" directives.
extern "C" linkage specification to declare any
modules that are written in C++ and called from other languages.
NOTE: HP aC++ classes are not accessible to non-C++ routines.
Since C++ is for the most part a superset of C, many of the data types
are identical.
Both languages support the same primitive types of char, short, int,
long, float, and double.
ANSI C and HP C++ also support a long double type.
In addition, HP aC++ supports bool, wchar_t, long long, and
unsigned long long data types.
Pointers, structs, and unions that can be declared in C are also compatible. Arrays composed of any of the above types are compatible.
C++ classes are generally incompatible with C structs. The following features of the C++ class facility may cause the compiler to generate extra code, extra fields, or data tables:
private
and public data members in a class)
It is the use of these features, as opposed to whether the class
keyword is used rather than struct, that introduces incompatibilities
with C structs.
Since C++ is for the most part a superset of C, calling between C and C++ is a normal operation. You should, however, be aware of the following:
extern "C" linkage specification to declare C functions.
To handle overloaded function names the HP aC++ compiler generates new, unique names for all functions declared in a C++ program. To do so, the compiler uses a function-name encoding scheme that is implementation dependent. A linkage directive tells the compiler to inhibit this default encoding of a function name for a particular function.
If you want to call a C function from a C++ program, you must tell the compiler not to use its usual encoding scheme when you declare the C function. In other words, you must tell the compiler not to generate a new name for the function. If you don't turn off the usual encoding scheme, the function name declared in your C++ program won't match the function name in your C module defining the function. If the names don't match, the linker cannot resolve them. To avoid these linkage problems, use a linkage directive when you declare the C function in the C++ program.
extern "C" function_declaration
extern "C"
{
function_declaration1
function_declaration2
...
function_declarationN
}
extern "C" char* get_name(); // declare the external C moduleand
extern "C"
{
char* get_name(); // declare the external C module
}
You can also use a linkage directive with all the functions in a file, as
shown in the following example. This is useful if you wish to use C library
functions in a C++ program.
extern "C"
{
#include "myclibrary.h"
}
NOTE:
Do not use extern "C" when including standard C header files
because these header files already contain extern "C" directives.
Although the string literal following the extern keyword
in a linkage directive is implementation-dependent, all implementations
must support C and C++ string literals. Refer to "Linkage
Specifications" in The C++ Programming Language, Third Edition.
If your C++ code calls functions written in C, you should make sure that the called C functions do not use function prototypes that suppress argument widening. If they do, your C++ code will be passing "wider" arguments than your C code is expecting.
main() function should appear in some C++ module, rather than in a C
module. The exceptions are C++ programs and libraries, including
HP-supplied libraries, without any global class objects containing
constructors or destructors and C++ programs and libraries, including
HP-supplied libraries, without static objects.
calling_c.C,
that calls a C function, get_name().
The C++ program contains a main() function.
//************************************************************
// This is a C++ program that illustrates calling a function *
// written in C. It calls the get_name() function, which is *
// in the "get_name.c" module. The object modules generated *
// by compiling the "calling_c.C" module and by compiling *
// the "get_name.c" module must be linked to create an *
// executable file. *
//************************************************************
#include <iostream.h>
#include "string.h"
//************************************************************
// declare the external C module
extern "C" char* get_name();
class account
{
private:
char* name; // owner of the account
protected:
double balance; // amount of money in the account
public:
account(char* c) // constructor
{ name = new char [strlen(c) +1];
strcpy(name,c);
balance = 0; }
void display()
{ cout << name << " has a balance of "
<< balance << "\n"; }
};
int main()
{
account* my_checking_acct = new account (get_name());
// send a message to my_checking_account to display itself
my_checking_acct->display();
}
The following example shows the module get_name.c. This
function is called by the C++ program.
/****************************************************/
/* This is a C function that is called by main() in */
/* a C++ module, "calling_c.C". The object */
/* modules generated by compiling this module and */
/* by compiling the "calling_c.C" module must be */
/* linked to create an executable file. */
/****************************************************/
#include <stdio.h>
#include "string.h"
char* get_name()
{
static char name[80];
printf("Enter the name: ");
scanf("%s",name);
return name;
}
/****************************************************/
calling_c.C
and get_name.c:
Enter the name: Joann Joann has a balance of 0
When mixing C++ modules with C modules, usually the overall control of
the program must be written in C++.
In other words, the main() function must appear in some C++ module,
rather than in a C module, and you must link using aCC.
The two exceptions to this rule are
C++ programs and libraries (including HP-supplied libraries)
without any global class objects containing constructors or destructors and
C++ programs and libraries (including HP-supplied libraries) without
static objects.
Since most C++ programs use the
HP aC++ run-time libraries,
few programs meet these restrictions.
Therefore, you can call a C++ module from a C module by
following the points below, as well as the points in General Information When Calling Other Languages:
extern "C".
_main as the first
executable statement in main(). Object libraries require this
as _main calls the static constructors to initialize
the libraries' static data items.
NOTE:
64-bit mode differs from the above.
In 64-bit mode, your code must not call _main.
The following example programs illustrate some of the above points, as well as reference parameters in the interface routine to the constructor.
//**************************************************
// C++ module that manipulates object obj. *
//**************************************************
#include <iostream.h>
typedef class obj* obj_ptr;
extern "C" void initialize_obj (obj_ptr& p);
extern "C" void delete_obj (obj_ptr p);
extern "C" void print_obj (obj_ptr p);
struct obj {
private:
int x;
public:
obj() {x = 7;}
friend void print_obj(obj_ptr p);
};
// C interface routine to initialize an
// object by calling the constructor.
void initialize_obj(obj_ptr& p) {
p = new obj;
}
// C interface routine to destroy an
// object by calling the destructor.
void delete_obj(obj_ptr p) {
delete p;
}
// C interface routine to display
// manipulating the object.
void print_obj(obj_ptr p) {
cout << "the value of object->x is " << p->x << "\n";
}
Following is a C program that calls the C++ module to manipulate the object:
/***************************************************/
/* C program to demonstrate an interface to the */
/* C++ module. Note that the application needs */
/* to be linked with the aCC driver. */
/***************************************************/
typedef struct obj* obj_ptr;
int main () {
/* C++ object. Notice that none of the
routines should try to manipulate the fields.
/*
obj_ptr f;
/* The first executable statement needs to be a call
to _main so that static objects will be created in
libraries that have constructors defined. In this
application, the stream library contains data
elements that match the conditions.
/* NOTE: In 64-bit mode, you MUST NOT call _main.
#ifndef __LP64__
_main();
#endif
/* Initialize the data object. Notice taking
the address of f is compatible with the
C++ reference construct.
/*
initialize_obj(&f);
/* Call the routine to manipulate the fields */
print_obj(f);
/* Destroy the data object */
delete_obj(f);
}
cc -c cfilename.c aCC -c C++filename.C aCC -o executable cfilename.o C++filename.o
CAUTION:
During the linking phase, the aCC driver
program performs several functions to support the C++ class mechanism.
Linking programs that use classes with the C compiler driver cc
leads to unpredictable results at run time.
This section covers the following topics:
main() Function
extern "C" Linkage
NOTE: As is the case with calling HP C from HP aC++, you must link your application using HP aC++.
In general, when mixing C++ modules with modules in HP Pascal and
HP FORTRAN 90, the overall control of the program must be written
in C++. In other words, the main() function must appear in
some C++ module and no other outer block should be present.
If you wish to have a main() function in a module other than a C++
module, you can add a call to _main() as the first non-declarative
statement in the module. However, if you use this method, your code is not
portable.
When calling an HP Pascal or HP FORTRAN 90 function from HP aC++ you must keep in mind the differences between the way the languages handle case sensitivity. HP FORTRAN 90 and HP Pascal are not case sensitive, while HP aC++ is case sensitive. Therefore, all C++ global names accessed by FORTRAN 90 or Pascal routines must be lowercase. All FORTRAN 90 and Pascal external names are downshifted by default.
There are two methods of passing arguments, by reference or by value. Passing by reference means that the routine passes the address of the argument rather than the value of the argument.
When calling HP Pascal or HP FORTRAN 90 functions from HP aC++, you need to ensure that the caller and called functions use the same method of argument passing for each individual argument. Furthermore, when calling external functions in HP Pascal or HP FORTRAN 90, you must know the calling convention for the order of arguments.
It is not recommended that you pass structures or classes to HP FORTRAN 90 or HP Pascal. For maximum compatibility and portability, only simple data types should be passed to routines. All HP aC++ parameters are passed by value, as in HP C, except arrays and functions which are passed as pointers.
HP FORTRAN 90 passes all arguments by reference. This
means that all actual parameters in an HP aC++ call to a FORTRAN routine
must be pointers, or variables prefixed with the unary address operator,
&.
HP Pascal passes arguments by value, unless specified as var
parameters. There are two ways to pass variables to Pascal var parameters.
One way is to use the address operator, &.
The other way is to declare the variable as a pointer to the appropriate
type, assign the address to the pointer, and pass the pointer.
So, the simplest way to reconcile these differences in argument-passing conventions is to use reference variables in your C++ code. Declaring a parameter as a reference variable in a prototype causes the compiler to pass the argument by reference when the function is invoked.
int main( void )
{
// declare a reference variable
extern void pas_func( short & );
short x;
...
pas_func( x ); // pas_func should accept
... // its parameters by reference
}
Refer to "References" in The C++ Programming Language, Third Edition for details about using reference variables.
If you want to mix C++ modules with HP FORTRAN 90 or HP Pascal
modules, be sure to use extern "C" linkage to declare
any C++ functions that are called from a non-C++ module and
to declare the FORTRAN or Pascal routines.
HP aC++ strings are not the same as HP FORTRAN 90 strings. In FORTRAN 90 the strings are not null terminated. Also, strings are passed as string descriptors in FORTRAN 90. This means that the address of the character item is passed and a length by value follows.
NOTE:
If you use the HP FORTRAN 90 +800 option, the length follows immediately
after the character pointer in the parameter list. If you do not use this
option, HP FORTRAN 90 passes character lengths by value at the end of the
parameter list. See the HP FORTRAN/9000 Programmer's Reference and the
HP FORTRAN/9000 Programmer's Guide for information about the +800
option.
HP Pascal strings and HP aC++ strings are not compatible. See your HP Pascal manual for details.
HP aC++ stores arrays in row-major order, whereas HP FORTRAN 90 stores arrays in column-major order. The lower bound for HP aC++ is 0. The default lower bound for HP FORTRAN 90 is 1. For HP Pascal, the lower bound may be any user-defined scalar value.
HP aC++ does not have a Pascal boolean type. On the HP 9000 Series 700/800, HP Pascal allocates 1 byte for boolean variables and only accesses the rightmost bit to determine its value, 1 to represent TRUE and 0 for FALSE.
On the HP 9000 Series 300/400, 2 bytes are allocated for a boolean and any nonzero value represents TRUE and 0 represents FALSE. On the HP 9000 Series 300/400, HP aC++ and HP Pascal do share a common definition of TRUE and FALSE.
HP FORTRAN I/O routines require a logical unit number to access a file, whereas HP aC++ accesses files using HP-UX I/O subroutines and intrinsics and requires a stream pointer.
A FORTRAN logical unit cannot be passed to a C++ routine to perform I/O on the associated file, nor can a C++ file pointer be used by a FORTRAN routine. However, a file created by a program written in either language can be used by a program of the other language if the file is declared opened within the latter program. HP-UX I/O (stream I/O) can also be used from FORTRAN instead of FORTRAN I/O.
Refer to your system FORTRAN manual on inter-language calls for details.
If I/O from Pascal is required, it is recommended that you use HP-UX input/output routines and intrinsics. This allows C++ and Pascal to use the same I/O mechanism.
See the HP Pascal manual for your system for more details.
When calling HP FORTRAN 90 routines on the HP 9000 Series 700/800, you must include the appropriate run-time libraries by adding the following argument to the aCC command when linking your program:
-lisamstub
CC command
are needed when linking your program. Simply use the aCC
command and include your Pascal object files.