RSS Feed
Download our iPhone app
Browse DevX
Sign up for e-mail newsletters from DevX


A Guide to C++ and C Interoperability  : Page 3

Using C++ code in C apps is difficult and tricky, though not impossible, contrary to popular belief. Find out how to share class declarations between the two languages and how to leverage C apps with high-end C++ features behind your C compiler's back.

ABI Issues
You probably noticed that String doesn't define a constructor, a destructor or an assignment operator. This wasn't an oversight. In spite of its C++ interface, String still remains a POD type, which means that its binary layout is identical in C and C++. Indeed, you're limited with respect to the C++ features that you may add to String but you still have enough leeway to make C++ users content. To summarize, adding any of the following features to String will make it a non-POD type:
  • virtual functions
  • user-defined destructor
  • user-defined assignment operator
  • user-defined copy constructor
  • user-defined constructor
  • reference members
  • data members that are pointers to members
  • base class(es)
  • non-POD member objects

Using C++ Functionality in C
Thus far, this article has focused on the source code level of sharing declarations between the two languages. You can also utilize compiled C++ functionality in C by wrapping C++ code in an intermediary layer. Here's an example.

Suppose you're maintaining a C application that reads char* strings and stores them as char**. Your task is to sort these strings alphabetically and print them onscreen. Instead of wading through strcmp(), qsort() and pointer mayhem, you want an elegant, STL-based solution. It's doable.

First, declare an intermediary function as extern "C". This function will be compiled as a C++ function but it's callable from C, too. C doesn't recognize the extern "C" linkage specification. Therefore, use #ifdef-#endif to hide this part from the C compiler:

// func.h
#ifdef __cplusplus
 extern "C" 
void func (char **s, int n);
// end of func.h
func() is implemented in a .cpp source file that's compiled separately. Here's a typical implementation that uses all sorts of STL conveniences:

#include <iostream>
#include <vector>
#include <iterator>
#include <algorithm>
#include <string>

extern "C" void func (char **s, int n)
 vector<string> vs;
 for (int i=0; i<n; i++)
 sort(vs.begin(), vs.end());
 //print the contents of vs using a stream iterator
Compile func() as usual. Next, add its declaration to your C application:

#include "func.h"
int main()
 char *strings[4]={{"bcd"},{"abc"},{"efg"},{"aaa"}};
 func(strings, 4);
A C compiler doesn't care how func() is implemented; it only inserts a call to a function with this name into main.obj. It's the linker's job to resolve the call to the same function defined in func.obj. Since the linker sees only the .obj files, the extern "C" linkage specification is mandatory. It guarantees that both C and C++ generate the same symbol for func(). Without extern "C", you'll get a linkage error.

Can func() use any C++ feature? Yes, almost. Virtually all implementations nowadays use a single runtime library for C and C++ so yanking compiled C++ code into C should "just work". There's one caveat, though: C functions do not propagate C++ exceptions. If func() throws an exception, your application will behave unpredictably. To avoid this, func() must handle all exceptions, if any, locally.

Danny Kalev is a certified system analyst and software engineer specializing in C++. He was a member of the C++ standards committee between 1997 and 2000 and has since been involved informally in the C++0x standardization process. He is the author of "The ANSI/ISO Professional C++ Programmer's Handbook" and "The Informit C++ Reference Guide: Techniques, Insight, and Practical Advice on C++."
Email AuthorEmail Author
Close Icon
Thanks for your registration, follow us on our social networks to keep up-to-date