1९ इन स स क त - 19 in sa sa ka ta

The C++ language provides mechanisms for mixing code that is compiled by compatible C and C++ compilers in the same program. You can experience varying degrees of success as you port such code to different platforms and compilers. This article shows how to solve common problems that arise when you mix C and C++ code, and highlights the areas where you might run into portability issues. In all cases we show what is needed when using Oracle Developer Studio C and C++ compilers.

Contents

  • Using Compatible Compilers
  • Accessing C Code from Within C++ Source
  • Accessing C++ Code from Within C Source
  • Accessing C++ Classes from C
  • Mixing IOstream and C Standard I/O
  • Working with Pointers to Functions
  • Working with C++ Exceptions
  • Linking the Program

Using Compatible Compilers

The first requirement for mixing code is that the C and C++ compilers you are using must be compatible. They must, for example, define basic types such as int, float or pointer in the same way. The Oracle Solaris operating system specifies the Application Binary Interface (ABI) of C programs, which includes information about basic types and how functions are called. Any useful compiler for Oracle Solaris must follow this ABI.

Oracle Developer Studio C and C++ compilers follow the Oracle Solaris ABI and are compatible. Third-party C compilers for Oracle Solaris usually also follow the ABI. Any C compiler that is compatible with the Oracle Developer Studio C compiler is also compatible with the Oracle Developer Studio C++ compiler.

The C runtime library used by your C compiler must also be compatible with the C++ compiler. C++ includes the standard C runtime library as a subset, although there are a few differences. If the C++ compiler provides its own versions of the C headers, the versions of those headers used by the C compiler must be compatible.

Oracle Developer Studio C and C++ compilers use compatible headers, and use the same C runtime library. They are fully compatible.

Accessing C Code from Within C++ Source

The C++ language provides a "linkage specification" with which you declare that a function or object follows the program linkage conventions for a supported language. The default linkage for objects and functions is C++. All C++ compilers also support C linkage, for some compatible C compiler.

When you need to access a function compiled with C linkage (for example, a function compiled by the C compiler, or a function written in assembler), declare the function to have C linkage. Even though most C++ compilers do not have different linkage for C and C++ data objects, you should declare C data objects to have C linkage in C++ code. With the exception of the pointer-to-function type, types do not have C or C++ linkage.

Declaring Linkage Specifications

Use one of the following notations to declare that an object or function has the linkage of language language_name:

Copy



extern "language_name" declaration ;
extern "language_name" { declaration ; declaration ; ... }


The first notation indicates that the declaration (or definition) that immediately follows has the linkage of language_name. The second notation indicates that everything between the curly braces has the linkage of language_name, unless declared otherwise. Notice that you do not use a semicolon after the closing curly brace in the second notation.

You can nest linkage specifications, but the braces do not create scopes. Consider the following example:

Copy

extern "C" {
    void f();              // C linkage
    extern "C++" {
        void g();          // C++ linkage
        extern "C" void h(); // C linkage
        void g2();         // C++ linkage
    }
    extern "C++" void k(); // C++ linkage
    void m();              // C linkage
}

All the functions above are in the same global scope, despite the nested linkage specifiers.

Including C Headers in C++ Code

If you want to use a C library with its own defining header that was intended for C compilers, you can include the header in

extern "C" {
    void f();              // C linkage
    extern "C++" {
        void g();          // C++ linkage
        extern "C" void h(); // C linkage
        void g2();         // C++ linkage
    }
    extern "C++" void k(); // C++ linkage
    void m();              // C linkage
}

9 brackets:

Copy

extern "C" {
    #include "header.h"

}

Warning: Do not use this technique for system headers on Oracle Solaris. Oracle Solaris headers, and all the headers that come with Oracle Developer Studio C and C++ compilers, are already configured for use with C and C++ compilers. You can invalidate declarations in Oracle Solaris headers if you specify a linkage.

Note: For other than system headers, check to see whether the header was written to work with C++ compilers; that is, whether it already has linkage specifications. If so, you should not enclose the header in

extern "C" {
    void f();              // C linkage
    extern "C++" {
        void g();          // C++ linkage
        extern "C" void h(); // C linkage
        void g2();         // C++ linkage
    }
    extern "C++" void k(); // C++ linkage
    void m();              // C linkage
}

9 brackets.

Creating Mixed-Language Headers

If you want to make a header suitable for both C and C++ compilers, you could put all the declarations inside

extern "C" {
    void f();              // C linkage
    extern "C++" {
        void g();          // C++ linkage
        extern "C" void h(); // C linkage
        void g2();         // C++ linkage
    }
    extern "C++" void k(); // C++ linkage
    void m();              // C linkage
}

9 brackets, but the C compiler does not recognize the syntax. Every C++ compiler predefines the macro
extern "C" {
    #include "header.h"

}

2, so you can use that macro to guard the C++ syntax extensions:

Copy


#ifdef __cplusplus
extern "C" {
#endif

... // body of header

#ifdef __cplusplus
} // closing brace for extern "C"

#endif

Adding C++ Features to C Structs

Suppose you want to make it easier to use a C library in your C++ code. And suppose that instead of using C-style access, you want to add virtual or non-virtual member functions, derive from the class, and so on. How can you accomplish this transformation and ensure the C library functions can still recognize the struct? Consider the uses of the C

extern "C" {
    #include "header.h"

}

3 in the following example:

Copy


struct buf {
    char* data;
    unsigned count;
};
void buf_clear(struct buf*);
int  buf_print(struct buf*); // return status, 0 means fail
int  buf_append(struct buf*, const char*, unsigned count); // same return

You want to turn this struct into a C++ class and make it easier to use with the following changes:

Copy


  extern "C" {
  #include "buf.h"

}
class mybuf { // first attempt -- will it work?
public:
    mybuf() : data(0), count(0) { }
    void clear() { buf_clear( (buf*)this ); }
    bool print() { return buf_print( (buf*)this ); }
    bool append(const char* p, unsigned c)
        { return buf_append( (buf*)this, p, c ); }
private:
    char* data;
    unsigned count;
};

The interface to the

extern "C" {
    #include "header.h"

}

4 looks more like C++ code, and can be more easily integrated into an object-oriented style of programming -- if it works.

What happens when the member functions pass the

extern "C" {
    #include "header.h"

}

5 pointer to the
extern "C" {
    #include "header.h"

}

6 functions? Does the C++ class layout match the C layout? Does the
extern "C" {
    #include "header.h"

}

5 pointer point to the
extern "C" {
    #include "header.h"

}

8 member, as a pointer to
extern "C" {
    #include "header.h"

}

6 does? What if you add virtual functions to

#ifdef __cplusplus
extern "C" {
#endif

... // body of header

#ifdef __cplusplus
} // closing brace for extern "C"

#endif

0?

The C++ standard makes no promises about the compatibility of

extern "C" {
    #include "header.h"

}

3 and
extern "C" {
    #include "header.h"

}

4. This code, without virtual functions, might work, but you can't count on it. If you add virtual functions, the code will fail using compilers that add extra data (such as pointers to virtual tables) at the beginning of a class.

The portable solution is to leave

extern "C" {
    #include "header.h"

}

3 strictly alone, even though you would like to protect the data members and provide access only through member functions. You can guarantee C and C++ compatibility only if you leave the declaration unchanged.

You can derive a C++

extern "C" {
    #include "header.h"

}

4 from the C
extern "C" {
    #include "header.h"

}

3, and pass pointers to the
extern "C" {
    #include "header.h"

}

6 base class to the

#ifdef __cplusplus
extern "C" {
#endif

... // body of header

#ifdef __cplusplus
} // closing brace for extern "C"

#endif

0 functions. If a pointer to

#ifdef __cplusplus
extern "C" {
#endif

... // body of header

#ifdef __cplusplus
} // closing brace for extern "C"

#endif

0 doesn't point to the beginning of the
extern "C" {
    #include "header.h"

}

6 data, the C++ compiler will adjust it automatically when converting a

struct buf {
    char* data;
    unsigned count;
};
void buf_clear(struct buf*);
int  buf_print(struct buf*); // return status, 0 means fail
int  buf_append(struct buf*, const char*, unsigned count); // same return

0 to a

struct buf {
    char* data;
    unsigned count;
};
void buf_clear(struct buf*);
int  buf_print(struct buf*); // return status, 0 means fail
int  buf_append(struct buf*, const char*, unsigned count); // same return

1. The layout of

#ifdef __cplusplus
extern "C" {
#endif

... // body of header

#ifdef __cplusplus
} // closing brace for extern "C"

#endif

0 might vary among C++ compilers, but the C++ source code that manipulates

#ifdef __cplusplus
extern "C" {
#endif

... // body of header

#ifdef __cplusplus
} // closing brace for extern "C"

#endif

0 and
extern "C" {
    #include "header.h"

}

6 objects will work everywhere. The following example shows a portable way to add C++ and object-oriented features to a C struct.

Copy

  
extern "C" {
  #include "buf.h"
}
class mybuf : public buf { // a portable solution
public:
    mybuf() : data(0), count(0) { }
    void clear() { buf_clear(this); }
    bool print() { return buf_print(this); }
    bool append(const char* p, unsigned c)
        { return buf_append(this, p, c); }
};

C++ code can freely create and use


#ifdef __cplusplus
extern "C" {
#endif

... // body of header

#ifdef __cplusplus
} // closing brace for extern "C"

#endif

0 objects, passing them to C code that expects
extern "C" {
    #include "header.h"

}

6 objects, and everything will work together. Of course, if you add data to

#ifdef __cplusplus
extern "C" {
#endif

... // body of header

#ifdef __cplusplus
} // closing brace for extern "C"

#endif

0, the C code won't know anything about it. That's a general design consideration for class hierarchies. You also have to take care to create and delete
extern "C" {
    #include "header.h"

}

6 and

#ifdef __cplusplus
extern "C" {
#endif

... // body of header

#ifdef __cplusplus
} // closing brace for extern "C"

#endif

0 objects consistently. It is safest to let C code delete (

  extern "C" {
  #include "buf.h"

}
class mybuf { // first attempt -- will it work?
public:
    mybuf() : data(0), count(0) { }
    void clear() { buf_clear( (buf*)this ); }
    bool print() { return buf_print( (buf*)this ); }
    bool append(const char* p, unsigned c)
        { return buf_append( (buf*)this, p, c ); }
private:
    char* data;
    unsigned count;
};

0) an object if it was created by C code, and not allow C code to delete a

#ifdef __cplusplus
extern "C" {
#endif

... // body of header

#ifdef __cplusplus
} // closing brace for extern "C"

#endif

0 object.

Accessing C++ Code from Within C Source

If you declare a C++ function to have C linkage, it can be called from a function compiled by the C compiler. A function declared to have C linkage can use all the features of C++, but its parameters and return type must be accessible from C if you want to call it from C code. For example, if a function is declared to take a reference to an IOstream class as a parameter, there is no (portable) way to explain the parameter type to a C compiler. The C language does not have references or templates or classes with C++ features.

Here is an example of a C++ function with C linkage:

Copy


#include <iostream>
extern "C" int print(int i, double d)
{
    std::cout << "i = " << i << ", d = " << d;
}


You can declare function


  extern "C" {
  #include "buf.h"

}
class mybuf { // first attempt -- will it work?
public:
    mybuf() : data(0), count(0) { }
    void clear() { buf_clear( (buf*)this ); }
    bool print() { return buf_print( (buf*)this ); }
    bool append(const char* p, unsigned c)
        { return buf_append( (buf*)this, p, c ); }
private:
    char* data;
    unsigned count;
};

2 in a header file that is shared by C and C++ code:

Copy


#ifdef __cplusplus
extern "C"
#endif
int print(int i, double d);

You can declare at most one function of an overloaded set as

extern "C" {
    void f();              // C linkage
    extern "C++" {
        void g();          // C++ linkage
        extern "C" void h(); // C linkage
        void g2();         // C++ linkage
    }
    extern "C++" void k(); // C++ linkage
    void m();              // C linkage
}

9 because only one C function can have a given name. If you need to access overloaded functions from C, you can write C++ wrapper functions with different names as the following example demonstrates:

Copy


int    g(int);
double g(double);
extern "C" int    g_int(int i)       { return g(i); }
extern "C" double g_double(double d) { return g(d); }

Here is the example C header for the wrapper functions:

Copy

extern "C" {
    void f();              // C linkage
    extern "C++" {
        void g();          // C++ linkage
        extern "C" void h(); // C linkage
        void g2();         // C++ linkage
    }
    extern "C++" void k(); // C++ linkage
    void m();              // C linkage
}

0

You also need wrapper functions to call template functions because template functions cannot be declared as

extern "C" {
    void f();              // C linkage
    extern "C++" {
        void g();          // C++ linkage
        extern "C" void h(); // C linkage
        void g2();         // C++ linkage
    }
    extern "C++" void k(); // C++ linkage
    void m();              // C linkage
}

9:

Copy

extern "C" {
    void f();              // C linkage
    extern "C++" {
        void g();          // C++ linkage
        extern "C" void h(); // C linkage
        void g2();         // C++ linkage
    }
    extern "C++" void k(); // C++ linkage
    void m();              // C linkage
}

1

C++ code can still call the overloaded functions and the template functions. C code must use the wrapper functions.

Accessing C++ Classes from C

Can you access a C++ class from C code? Can you declare a C struct that looks like a C++ class and somehow call member functions? The answer is yes, although to maintain portability you must add some complexity. Also, any modifications to the definition of the C++ class you are accessing requires that you review your C code.

Suppose you have a C++ class such as the following:

Copy

extern "C" {
    void f();              // C linkage
    extern "C++" {
        void g();          // C++ linkage
        extern "C" void h(); // C linkage
        void g2();         // C++ linkage
    }
    extern "C++" void k(); // C++ linkage
    void m();              // C linkage
}

2

You cannot declare class


  extern "C" {
  #include "buf.h"

}
class mybuf { // first attempt -- will it work?
public:
    mybuf() : data(0), count(0) { }
    void clear() { buf_clear( (buf*)this ); }
    bool print() { return buf_print( (buf*)this ); }
    bool append(const char* p, unsigned c)
        { return buf_append( (buf*)this, p, c ); }
private:
    char* data;
    unsigned count;
};

5 in your C code. The best you can do is to pass around pointers to class

  extern "C" {
  #include "buf.h"

}
class mybuf { // first attempt -- will it work?
public:
    mybuf() : data(0), count(0) { }
    void clear() { buf_clear( (buf*)this ); }
    bool print() { return buf_print( (buf*)this ); }
    bool append(const char* p, unsigned c)
        { return buf_append( (buf*)this, p, c ); }
private:
    char* data;
    unsigned count;
};

5 objects, like the way you deal with FILE objects in C Standard I/O. You can write
extern "C" {
    void f();              // C linkage
    extern "C++" {
        void g();          // C++ linkage
        extern "C" void h(); // C linkage
        void g2();         // C++ linkage
    }
    extern "C++" void k(); // C++ linkage
    void m();              // C linkage
}

9 functions in C++ that access class

  extern "C" {
  #include "buf.h"

}
class mybuf { // first attempt -- will it work?
public:
    mybuf() : data(0), count(0) { }
    void clear() { buf_clear( (buf*)this ); }
    bool print() { return buf_print( (buf*)this ); }
    bool append(const char* p, unsigned c)
        { return buf_append( (buf*)this, p, c ); }
private:
    char* data;
    unsigned count;
};

5 objects and call them from C code. Here is a C++ function designed to call the member function

  extern "C" {
  #include "buf.h"

}
class mybuf { // first attempt -- will it work?
public:
    mybuf() : data(0), count(0) { }
    void clear() { buf_clear( (buf*)this ); }
    bool print() { return buf_print( (buf*)this ); }
    bool append(const char* p, unsigned c)
        { return buf_append( (buf*)this, p, c ); }
private:
    char* data;
    unsigned count;
};

9:

  
extern "C" {
  #include "buf.h"
}
class mybuf : public buf { // a portable solution
public:
    mybuf() : data(0), count(0) { }
    void clear() { buf_clear(this); }
    bool print() { return buf_print(this); }
    bool append(const char* p, unsigned c)
        { return buf_append(this, p, c); }
};

0

Here is an example of C code that uses class


  extern "C" {
  #include "buf.h"

}
class mybuf { // first attempt -- will it work?
public:
    mybuf() : data(0), count(0) { }
    void clear() { buf_clear( (buf*)this ); }
    bool print() { return buf_print( (buf*)this ); }
    bool append(const char* p, unsigned c)
        { return buf_append( (buf*)this, p, c ); }
private:
    char* data;
    unsigned count;
};

5:

Copy

extern "C" {
    void f();              // C linkage
    extern "C++" {
        void g();          // C++ linkage
        extern "C" void h(); // C linkage
        void g2();         // C++ linkage
    }
    extern "C++" void k(); // C++ linkage
    void m();              // C linkage
}

3

Mixing IOstream and C Standard I/O

You can use C Standard I/O from the standard C header <stdio.h> in C++ programs because C Standard I/O is part of C++.

Any considerations about mixing IOstream and Standard I/O in the same program therefore do not depend on whether the program contains C code specifically. The issues are the same for purely C++ programs that use both Standard I/O and IOstreams.

Oracle Developer Studio C and C++ use the same C runtime libraries, as noted in the section about compatible compilers. Using Oracle Developer Studio compilers, you can therefore use Standard I/O functions freely in both C and C++ code in the same program.

The C++ standard says you can mix Standard I/O functions and IOstream functions on the same target "stream", such as the standard input and output streams. But C++ implementations vary in their compliance. Some systems require that you call the

  
extern "C" {
  #include "buf.h"
}
class mybuf : public buf { // a portable solution
public:
    mybuf() : data(0), count(0) { }
    void clear() { buf_clear(this); }
    bool print() { return buf_print(this); }
    bool append(const char* p, unsigned c)
        { return buf_append(this, p, c); }
};

2function explicitly before doing any I/O. Implementations also vary in the efficiency of I/O when you mix I/O styles on the same stream or file. In the worst case, you get a system call per character input or output. If the program does a lot of I/O, the performance might be unacceptable.

The safest course is to use only one of Standard I/O or IOstream styles on any given file or standard stream. Using Standard I/O on one file or stream and IOstream on a different file or stream does not cause any problems.

Working with Pointers to Functions

A pointer to a function must specify whether it points to a C function or to a C++ function, because it is possible that C and C++ functions use different calling conventions. Otherwise, the compiler does not know which kind of function-calling code to generate. Most systems do not have different calling conventions for C and C++, but C++ allows for the possibility. You therefore must be careful about declaring pointers to functions, to ensure that the types match. Consider the following example:

Copy

extern "C" {
    void f();              // C linkage
    extern "C++" {
        void g();          // C++ linkage
        extern "C" void h(); // C linkage
        void g2();         // C++ linkage
    }
    extern "C++" void k(); // C++ linkage
    void m();              // C linkage
}

4

  • Line 1 declares
      
    extern "C" {
      #include "buf.h"
    }
    class mybuf : public buf { // a portable solution
    public:
        mybuf() : data(0), count(0) { }
        void clear() { buf_clear(this); }
        bool print() { return buf_print(this); }
        bool append(const char* p, unsigned c)
            { return buf_append(this, p, c); }
    };
    
    
    3 to point to a C++ function, because it lacks a linkage specifier.
  • Line 2 therefore declares
    
      extern "C" {
      #include "buf.h"
    
    }
    class mybuf { // first attempt -- will it work?
    public:
        mybuf() : data(0), count(0) { }
        void clear() { buf_clear( (buf*)this ); }
        bool print() { return buf_print( (buf*)this ); }
        bool append(const char* p, unsigned c)
            { return buf_append( (buf*)this, p, c ); }
    private:
        char* data;
        unsigned count;
    };
    
    
    9 to be a C function that takes a pointer to a C++ function.
  • Line 5 attempts to call
    
      extern "C" {
      #include "buf.h"
    
    }
    class mybuf { // first attempt -- will it work?
    public:
        mybuf() : data(0), count(0) { }
        void clear() { buf_clear( (buf*)this ); }
        bool print() { return buf_print( (buf*)this ); }
        bool append(const char* p, unsigned c)
            { return buf_append( (buf*)this, p, c ); }
    private:
        char* data;
        unsigned count;
    };
    
    
    9 with a pointer to
      
    extern "C" {
      #include "buf.h"
    }
    class mybuf : public buf { // a portable solution
    public:
        mybuf() : data(0), count(0) { }
        void clear() { buf_clear(this); }
        bool print() { return buf_print(this); }
        bool append(const char* p, unsigned c)
            { return buf_append(this, p, c); }
    };
    
    
    6, a C function, a type mismatch.

Be sure to match the linkage of a pointer-to-function with the functions to which it will point. In the following corrected example, all declarations are inside

extern "C" {
    void f();              // C linkage
    extern "C++" {
        void g();          // C++ linkage
        extern "C" void h(); // C linkage
        void g2();         // C++ linkage
    }
    extern "C++" void k(); // C++ linkage
    void m();              // C linkage
}

9 brackets, ensuring that the types match.

Copy

extern "C" {
    void f();              // C linkage
    extern "C++" {
        void g();          // C++ linkage
        extern "C" void h(); // C linkage
        void g2();         // C++ linkage
    }
    extern "C++" void k(); // C++ linkage
    void m();              // C linkage
}

5

Pointers to functions have one other subtlety that occasionally traps programmers. A linkage specification applies to all the parameter types and to the return type of a function. If you use the elaborated declaration of a pointer-to-function in a function parameter, a linkage specification on the function applies to the pointer-to-function as well. If you declare a pointer-to-function using a

  
extern "C" {
  #include "buf.h"
}
class mybuf : public buf { // a portable solution
public:
    mybuf() : data(0), count(0) { }
    void clear() { buf_clear(this); }
    bool print() { return buf_print(this); }
    bool append(const char* p, unsigned c)
        { return buf_append(this, p, c); }
};

8, the linkage specification of that
  
extern "C" {
  #include "buf.h"
}
class mybuf : public buf { // a portable solution
public:
    mybuf() : data(0), count(0) { }
    void clear() { buf_clear(this); }
    bool print() { return buf_print(this); }
    bool append(const char* p, unsigned c)
        { return buf_append(this, p, c); }
};

8 is not affected by using it in a function declaration. For example, consider this code:

Copy

extern "C" {
    void f();              // C linkage
    extern "C++" {
        void g();          // C++ linkage
        extern "C" void h(); // C linkage
        void g2();         // C++ linkage
    }
    extern "C++" void k(); // C++ linkage
    void m();              // C linkage
}

6

The first two lines might appear in a program file, and the third line might appear in a header where you don't want to expose the name of the private typedef. Although you intended for the declaration of


  extern "C" {
  #include "buf.h"

}
class mybuf { // first attempt -- will it work?
public:
    mybuf() : data(0), count(0) { }
    void clear() { buf_clear( (buf*)this ); }
    bool print() { return buf_print( (buf*)this ); }
    bool append(const char* p, unsigned c)
        { return buf_append( (buf*)this, p, c ); }
private:
    char* data;
    unsigned count;
};

9 and its definition to match, they do not. The definition of

  extern "C" {
  #include "buf.h"

}
class mybuf { // first attempt -- will it work?
public:
    mybuf() : data(0), count(0) { }
    void clear() { buf_clear( (buf*)this ); }
    bool print() { return buf_print( (buf*)this ); }
    bool append(const char* p, unsigned c)
        { return buf_append( (buf*)this, p, c ); }
private:
    char* data;
    unsigned count;
};

9 takes a pointer to a C++ function, but the declaration of

  extern "C" {
  #include "buf.h"

}
class mybuf { // first attempt -- will it work?
public:
    mybuf() : data(0), count(0) { }
    void clear() { buf_clear( (buf*)this ); }
    bool print() { return buf_print( (buf*)this ); }
    bool append(const char* p, unsigned c)
        { return buf_append( (buf*)this, p, c ); }
private:
    char* data;
    unsigned count;
};

9 takes a pointer to a C function. The code declares a pair of overloaded functions. You might find that the program fails to link to due an unresolved symbol.

To avoid this problem, use typedefs consistently in declarations, or enclose the typedefs in appropriate linkage specifications. For example, assuming you wanted


  extern "C" {
  #include "buf.h"

}
class mybuf { // first attempt -- will it work?
public:
    mybuf() : data(0), count(0) { }
    void clear() { buf_clear( (buf*)this ); }
    bool print() { return buf_print( (buf*)this ); }
    bool append(const char* p, unsigned c)
        { return buf_append( (buf*)this, p, c ); }
private:
    char* data;
    unsigned count;
};

9 to take a pointer to a C function, you could write the definition of

  extern "C" {
  #include "buf.h"

}
class mybuf { // first attempt -- will it work?
public:
    mybuf() : data(0), count(0) { }
    void clear() { buf_clear( (buf*)this ); }
    bool print() { return buf_print( (buf*)this ); }
    bool append(const char* p, unsigned c)
        { return buf_append( (buf*)this, p, c ); }
private:
    char* data;
    unsigned count;
};

9 this way:

Copy

extern "C" {
    void f();              // C linkage
    extern "C++" {
        void g();          // C++ linkage
        extern "C" void h(); // C linkage
        void g2();         // C++ linkage
    }
    extern "C++" void k(); // C++ linkage
    void m();              // C linkage
}

7

Working with C++ Exceptions

Propagating Exceptions

What happens if you call a C++ function from a C function, and the C++ function throws an exception? The C++ standard is somewhat vague about whether you can expect exceptions to behave properly, and on some systems you have to take special precautions. Generally, you must consult the user manuals to determine whether the code will work properly.

No special precautions are necessary with Oracle Developer Studio C++. The exception mechanism in Oracle Developer Studio C++ does not affect the way functions are called. If a C function is active when a C++ exception is thrown, the C function is passed over in the process of handling the exception.

Mixing Exceptions with set_jmp and long_jmp

The best advice is not to use


#include <iostream>
extern "C" int print(int i, double d)
{
    std::cout << "i = " << i << ", d = " << d;
}


5 in programs that contain C++ code. The C++ exception mechanism and C++ rules about destroying objects that go out of scope are likely to be violated by a

#include <iostream>
extern "C" int print(int i, double d)
{
    std::cout << "i = " << i << ", d = " << d;
}


5, with unpredictable results. Some compilers integrate exceptions and

#include <iostream>
extern "C" int print(int i, double d)
{
    std::cout << "i = " << i << ", d = " << d;
}


5, allowing them to work together, but you should not depend on such behavior. Oracle Developer Studio C++ uses the same

#include <iostream>
extern "C" int print(int i, double d)
{
    std::cout << "i = " << i << ", d = " << d;
}


8 and

#include <iostream>
extern "C" int print(int i, double d)
{
    std::cout << "i = " << i << ", d = " << d;
}


5 as the C compiler.

Some C++ experts believe that


#include <iostream>
extern "C" int print(int i, double d)
{
    std::cout << "i = " << i << ", d = " << d;
}


5 should not be integrated with exceptions, due to the difficulty of specifying exactly how it should behave.

If you use


#include <iostream>
extern "C" int print(int i, double d)
{
    std::cout << "i = " << i << ", d = " << d;
}


5 in C code that you are mixing with C++, ensure that a

#include <iostream>
extern "C" int print(int i, double d)
{
    std::cout << "i = " << i << ", d = " << d;
}


5 does not cross over an active C++ function. If you cannot ensure that, see if you can compile that C++ code with exceptions disabled. You still might have problems if the destructors of local objects are bypassed.

Linking the Program

At one time, most C++ compilers required that function


#ifdef __cplusplus
extern "C"
#endif
int print(int i, double d);

3 be compiled by the C++ compiler. That requirement is not common today, and Oracle Developer Studio C++ does not require it. If your C++ compiler needs to compile the main function but you cannot do so for some reason, you can change the name of the C main function and call it from a wrapper version of C++

#ifdef __cplusplus
extern "C"
#endif
int print(int i, double d);

3. For example, change the name of the C main function to

#ifdef __cplusplus
extern "C"
#endif
int print(int i, double d);

5, and write this C++ code:

Copy

extern "C" {
    void f();              // C linkage
    extern "C++" {
        void g();          // C++ linkage
        extern "C" void h(); // C linkage
        void g2();         // C++ linkage
    }
    extern "C++" void k(); // C++ linkage
    void m();              // C linkage
}

8

Of course,


#ifdef __cplusplus
extern "C"
#endif
int print(int i, double d);

5 must be declared in the C code to return an int, and it will have to return an int value. As noted above, you do not need to go to this trouble with Oracle Developer Studio C++.

Even if your program is primarily C code but makes use of C++ libraries, you need to link C++ runtime support libraries provided with the C++ compiler into your program. The easiest and best way to do that is to use


#ifdef __cplusplus
extern "C"
#endif
int print(int i, double d);

7, the C++ compiler driver, to do the linking. The C++ compiler driver knows what libraries to link, and the order in which to link them. The specific libraries can depend on the options used when compiling the C++ code.

Suppose you have C program files


#ifdef __cplusplus
extern "C"
#endif
int print(int i, double d);

8,

#ifdef __cplusplus
extern "C"
#endif
int print(int i, double d);

9, and

int    g(int);
double g(double);
extern "C" int    g_int(int i)       { return g(i); }
extern "C" double g_double(double d) { return g(d); }

0, and you use a C++ library

int    g(int);
double g(double);
extern "C" int    g_int(int i)       { return g(i); }
extern "C" double g_double(double d) { return g(d); }

1. With Oracle Developer Studio C++, you would issue the command.


int    g(int);
double g(double);
extern "C" int    g_int(int i)       { return g(i); }
extern "C" double g_double(double d) { return g(d); }

2

The necessary C++ runtime libraries like libCrun and libCstd are linked automatically. The documentation for


int    g(int);
double g(double);
extern "C" int    g_int(int i)       { return g(i); }
extern "C" double g_double(double d) { return g(d); }

1 might require that you use additional link-time options. If you can't use the C++ compiler for some reason, you can use the

int    g(int);
double g(double);
extern "C" int    g_int(int i)       { return g(i); }
extern "C" double g_double(double d) { return g(d); }

4 option of the CC command to get the list of commands the compiler issues, and capture them into a shell script. Since the exact commands depend on command-line options, you should review the output from

int    g(int);
double g(double);
extern "C" int    g_int(int i)       { return g(i); }
extern "C" double g_double(double d) { return g(d); }

4 with any change of the command line.

For More Information

See the Oracle Developer Studio C/C++ Documentation for the latest information on the Oracle Developer Studio C and C++ compilers and tools, including man pages and readme files.

About the Author

Steve Clamage has been at Sun (now Oracle) since 1994, and is currently technical lead for the Oracle Developer Studio C++ compiler. He has been a member of the ANSI C++ Committee since its founding in 1990, and served as chair from 1995 through 2014.