2

gcc 4.4.4 c89

I was just reading a discussion at DevX about calling C++ code from C since I have to do something similar. I am just wondering what user Vijayan meant by "make sure that non POD types in C++ are opaque to C clients."

Many thanks for any suggestions,

Rob Kennedy
  • 161,384
  • 21
  • 275
  • 467
ant2009
  • 27,094
  • 154
  • 411
  • 609
  • 3
    Do you know what a POD type is? – James McNellis Jan 11 '11 at 02:43
  • @Rob. Yes, I forgot. Edited my answer with the link. – ant2009 Jan 11 '11 at 02:48
  • @James, This is the first I have heard of a POD type. – ant2009 Jan 11 '11 at 02:48
  • 4
    @ant2009: see http://stackoverflow.com/questions/146452/what-are-pod-types-in-c. "Opaque" means that C code isn't capable of validly manipulating the contents of an object that isn't of POD-type, because non-POD-types might have "C++ magic" going on in their structures that C doesn't know about and will trip over. Also, the definition of a non-POD type won't compile as C anyway, so the C client couldn't include the header even if it wanted to do something. – Steve Jessop Jan 11 '11 at 03:01
  • But then, even the definition of POD structs may fail to compile on C. Having a POD struct is by no means a guarantee you may include its definition into a C file. – Johannes Schaub - litb Jan 11 '11 at 05:07
  • @Johannes Schaub - litb: The definition of opaque types I'm familiar with is a type that's only declared, not defined (`struct Foo;`) and which therefore is manipulated via pointers only (`struct Foo* create(); void dispose(struct Foo*);`. Obviously, it wouldn't be legal C if you wrote `void dispose(Foo*);`, there's more to source compatibility than just the type definition itself. – MSalters Jan 11 '11 at 08:42

5 Answers5

3

C can only deal with POD types.

Consequently, you cannot pass objects of non-POD types to C programs (by value). Also, if you pass pointers of non-POD types to C programs, they can't interact with the objects pointed to.

C. K. Young
  • 219,335
  • 46
  • 382
  • 435
3

POD = Plain old data structure = C structs, no virtual methods, etc. You need to write wrapper functions for C to access non-POD types (i.e., classes).

More on POD: http://en.wikipedia.org/wiki/Plain_old_data_structure

EmeryBerger
  • 3,897
  • 18
  • 29
2

For a type to be opaque means you can't look inside it: it's a "black box" that can be passed around but not inspected or manipulated directly by the C code. You typically refer to the object using either heap-allocated memory and void*s, or using functions to determine the necessary length and buffers.

For example, a C++ object might contain a std::string, but the layout of a std::string is not specified in the C++ Standard, so you can't write C code that directly reads from or writes to the string (at least, not without having a total understanding of the std::string layout, manually revalidated every time the compiler/STL is updated).

So, to allow C code to access the object, you might write C-callable functions such as:

#if __cplusplus
extern "C" {
#endif
void*       object_new();
const char* object_get_string(void* p_object);
void        object_set_string(void* p_object, const char* s);
void        object_delete();
#if _cplusplus
}
#endif

With C++ implementation ala:

class Object { std::string string_; ... }
void* object_new() { return new Object; }
const char* object_get_string(void* p) { return ((Object*)p)->string_.c_str()); }
...

Here, the object_XXX functions provide the C code with a safe way to use the Object.

Tony Delroy
  • 102,968
  • 15
  • 177
  • 252
2

Making the type opaque means, as per the line in the link:

typedef struct base base ; /* opaque */

makes the name of the handle available to C code, but not the definition of the type. This means that the C code cannot access any members directly, but has to go through the interface functions.

Note that you do not have to make a cast to a generic , i.e. void*, pointer, although doing so is one option, as per 9dan's answer.

Note that such a style of interface is in my experience a very nice way to manage encapsulation even in pure C code, just as in the standard C streams library.

Keith
  • 6,756
  • 19
  • 23
1

Making opaque to clients means nothing special. C stream file I/O (FILE* f = fopen) API is the typical example that present opaque handle to clients.

Apparently C can not handle non-POD type so you must hide C++ implementation from C clients but provide access method.

Example:

C++ Implementation

class MyLibrary {
MyLibrary();
~MyLibrary();
int DoSomething();
...
}

Declaration for C clients

typedef void* OPAQUEHANDLE;

extern OPAQUEHANDLE MyLibrary_OpenLibrary();
extern void MyLibrary_CloseLibrary(OPAQUEHANDLE h);
extern int MyLibrary_DoSometing(OPAQUEHANDLE h);

Implementation for C clients (in .cpp file)

extern OPAQUEHANDLE MyLibrary_OpenLibrary()
{
    return new MyLibrary;
}

extern void MyLibrary_CloseLibrary(OPAQUEHANDLE h)
{
    delete (MyLibrary*) h;
}

extern int MyLibrary_DoSometing(OPAQUEHANDLE h)
{
    return ((MyLibrary*)h)->DoSomething();
}
9dan
  • 4,222
  • 2
  • 29
  • 44