Mixing C++ with Other Languages

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:


General Information When 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:


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:

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 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.

Syntax of extern "C"

All HP aC++ linkage directives must have either of the following formats:

extern "C" function_declaration

extern "C"
     {
     function_declaration1
     function_declaration2
          ...
     function_declarationN
     }

Examples of extern "C"

For instance, 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.

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.

HP aC++ Calling HP C: An Example

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's 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 below, as well as the points in General Information When Calling Other Languages:

The following example programs illustrate some of the above points, as well as reference parameters in the interface routine to the constructor.

HP C Calling HP aC++: An Example

//**************************************************
//  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 or IPF, 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 Example 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

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.


Calling HP FORTRAN 90 from HP aC++

This section covers the following topics:

NOTE: As is the case with calling HP C from HP aC++, you must link your application using HP aC++.

Function Naming Conventions

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.

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 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.

Example of Reference Variables as Arguments

The following example illustrates a reference variable.

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.

Using extern "C" Linkage

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.

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.

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.

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 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.

Linking HP FORTRAN 90 Routines

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