|
|
|
This section provides guidelines for linking HP aC++ modules
with modules written in HP C and HP FORTRAN 90 on HP 9000
Series 700/800 systems.
This section is organized into the following sections:
|
| Calling Other Languages |
|
A module is a file containing one or more variable or
function declarations, one or more function definitions,
or similar items logically grouped together. Mixing modules written
in C++ with modules written in C is relatively straightforward
since C++ is for the most part a superset of C.
Mixing C++ modules with modules in languages other than C is more
complicated. 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:
-
In general, the overall control of the program must be
written in C++. In other words, the main() function should
appear in a C++ module and no other outer block should be present.
-
You must pay attention to case-sensitivity conventions for
function names in the different languages.
-
You must make sure that the data types in the different
languages correspond. Do not mismatch data types for parameters
and return values.
-
Storage layouts for aggregates differ between languages.
-
You must use the 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.
-
You must use the extern "C" linkage specification to declare
any modules that are written in C++ and called from
other languages.
-
Do not use extern "C" when including standard C header
files because these header files already contain extern "C"
directives.
Note: HP aC++ classes are not accessible to non-C++ routines.
|
| Data Compatibility between C and C++ |
|
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:
- Multiple visibility of members (that is, having both
private and public data members in a class)
- Inheritance (either single or multiple)
- Virtual functions
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.
|
| HP aC++ Calling HP C |
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:
Using the extern "C" Linkage Specification
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 do not turn off the
usual encoding scheme, the function name declared in your C++
program will not match the function name in your C module defining
the function. If the names do not 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.
Syntax:
All HP aC++ linkage directives must have either of the following formats:
extern "C" function_declaration
extern "C"
{
function_declaration1
function_declaration2
...
function_declarationN
}
Example:
The following declarations are equivalent:
extern "C" char* get_name(); // declare the external C module
and
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 for more information.
Differences in Argument Passing Conventions
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.
The main() Function
When mixing C++ modules with C modules, the overall
control of the program must be written in C++, with two exceptions.
In other words, the 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.
Examples: HP aC++ Calling HP C
The following examples show a C++ program, 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;
}
/****************************************************/
Running the Example Program:
Here is a sample run of the executable file that results
when you link the object modules generated by compiling
calling_c.C and get_name.c:
Enter the name: Joann
Joann has a balance of 0
|
| HP C Calling HP aC++ |
|
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:
-
To prevent a function name from being mangled,
the function definition and all declarations used
by the C++ code must use extern "C".
-
Member functions of classes in C++ are not callable from C.
If a member function routine is needed, a non-member function
in C++ can be called from C which in turn calls the member
function.
-
Since the C program cannot directly create or destroy
C++ objects, it is the responsibility of the writer of
the C++ class library to define interface routines that
call constructors and destructors, and it is the responsibility
of the C user to call these interface routines to create such
objects before using them and to destroy them afterwards.
-
The C user should not try to define an equivalent struct
definition for the class definition in C++. The class
definition may contain bookkeeping information that is
not guaranteed to work on every architecture. All access
to members should be done in the C++ module.
The following sample 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. */
#if !defined(__LP64__) && !defined(__ia64)
_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);
}
Compiling and Running the Programs:
To compile the example, enter the following commands:
cc -c cfilename.c
aCC -c C++filename.C
aCC -o executable cfilename.o C++filename.o
Note: 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.
|
| Calling HP FORTRAN 90 from HP aC++ |
This section covers the following topics:
The main() Function
When mixing C++ modules with modules in 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.
Function Naming Conventions
When calling an 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 is not case sensitive,
while HP aC++ is case sensitive. Therefore, all C++ global names
accessed by FORTRAN 90 routines must be lowercase.
All FORTRAN 90 external names are downshifted by default.
Using Reference Variables to Pass Arguments
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 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 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. 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, &.
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.
Example:
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
}
Using extern "C" Linkage
If you want to mix C++ modules with HP FORTRAN 90 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.
Strings
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.
Arrays
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.
Files in HP FORTRAN
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.
|
|