HPlogo HP C++ Programmer's Guide: HP 9000 Series Workstations and Servers > Chapter 5 Inter-Language Communication

Calling HP C from HP C++

» 

Technical documentation

Complete book in PDF

 » Table of Contents

 » Index

Since C++ is essentially a superset of C, calling between C and C++ is a normal operation. You should, however, be aware of the following:

  • You must use the extern "C" linkage specification to declare the C functions.

  • Because of function prototypes, C++ has argument-widening rules that are different from C's rules.

  • The overall control of the program should be written in C++.

The following sections discuss these issues.

Using the extern "C" Linkage Specification

To handle overloaded function names the HP C++ 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.

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

extern "C" function_declaration



extern "C"

     {

     function_declaration1

     function_declaration2

          .

          .

          .

     function_declarationN

     }

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

}

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, and to "Type-Safe Linkage for C++" in the C++ Language System Selected Readings for more details about linkage specifications.

Differences in Argument Passing Conventions

By default, the HP C++ compiler in translator mode does not generate function prototypes in the C code it creates. As a result HP C applies the argument widening rules of C without prototyping. This means that char and short types are promoted to int, and float is promoted to double.

In programs written entirely in C++ this does not cause any problem, since the arguments are consistently handled within the program. However, 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.

In translator mode you can use the +a1 option with CC to tell the translator to emit function prototypes in the C code it generates. When you use +a1, the linker links in the ANSI version of libC.a

(or libC.sl), which is named libC.ansi.a (or libC.ansi.sl).

Compiler mode is compatible with translator mode even though no C code is generated. In compiler mode, when you use +a0, the default, parameters of type float are promoted to type double. When you use +a1, float parameters are not promoted, but are passed as type float.

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 programs without any global class objects containing constructors or destructors and programs without static objects.

Example 5-1 shows a C++ program, calling_c.C, that contains a main() function. In this example the C++ program calls a C function, get_name(). Example 5-2 shows the C function.

Figure 5-1 Example 5-1. A C++ Program Calling a C 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"; }

};

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 is example 5-2 showing the module get_name.c. This function is called by the C++ program in example 5-1.

Figure 5-2 Example 5-2. A C Function Called by a 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;

}

/****************************************************/

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: Janice

Janice has a balance of 0
© Hewlett-Packard Development Company, L.P.