search    
Hewlett-Packard
Mixing HP aC++ with Other Languages
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++
If you mix C++ modules with C modules refer to the Linking Your HP aC++ Libraries with Other Languages section in the "Distributing" topic. 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 you can call a C++ module from a C module using the following procedure:

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