简体   繁体   中英

How to map inherited C++ structs in C?

I try to access in a C program data received from a C++ library which has been originally designed with structure inheritance:

example:

// C++ data structures
typedef struct _Base
{
public:
    int id;
    wchar_t* name;
} Base;


typedef struct _Struct1 : Base
{
public:
    int valueCount;
} Struct1;


typedef struct _Struct2 : Base
{
public:
    int parentID;
    int amount;
} Struct2;

I tried using the following data structures in C for mapping.

typedef struct _Base
{
    int id;
    wchar_t* name;
} Base;


typedef struct _Struct1
{
    // Base struct data
    int id;
    wchar_t* name;

    int valueCount;
} Struct1;


typedef struct _Struct2
{
    // Base struct data
    int id;
    wchar_t* name;

    int parentID;
    int amount;
} Struct2;

But printing the data, it looks like I get wrong values.

Am I missing something, any reference on how C++ represents inherited structure internally?

Thanks in advance!

The C++11 rules on PODs ( What are Aggregates and PODs and how/why are they special? ) specify that don't allow mixing concrete base classes with data members, but in practice for most compilers having a single POD base class is equivalent to encapsulating that class as the first member.

Try specifying your C structs encapsulating the base struct:

typedef struct _Struct1
{
    Base base;
    int valueCount;
} Struct1;

Note that this won't work if the C++ classes are non-POD (eg have virtual methods).

You might be able to trick your C compiler to produce a structure with the same memory layout of a C++ class, and in many cases that will work, but this is a fairly shaky foundation to build on.

The portable way would be to write accessor functions. Be sure to declare them as extern "C" .

Illustrative example for a header file (not necessarily clean; typical caveats of writing code in a web form apply :-)):

#ifdef __cplusplus

// C++ declarations go here

class Foo
{
public:
   int bar;
};

// C calling conventions follow

extern "C" {

#else

// Make it so your C code can work with Foo* as an incomplete/not-dereferencable
// type.
typedef void Foo;

#endif

// Declare this in a C++ source file to return fooptr->bar
int foo_get_bar(Foo *fooptr);

#ifdef __cplusplus
} // extern "C"
#endif

One possibility to investigate is that the structs you've defined are correct, but that the aligmnents the compilers are using don't match. See:

http://en.wikipedia.org/wiki/Data_structure_alignment

Usually you can set the alignment using compiler switches or #pragma directives. You'd have to read your compiler documentation to find out about that. If you can't contact the authors of the C++ code, you may have to use a debugger to look at the raw memory you're receiving to work out what the alignment/padding is between the different values in the structures.

You can get this kind of problem if one program is compiled for a 64 bit machine and the other for a 32 bit machine. Or it could be down to the different compilers implementations.

You can try using a wrapper layer over the C++ library you are using to output values coming from the C++ to to C rather than using directly what is coming from C++ side. That could work if the overhead from the extra layer would not be significant.

Casting a C++ class might not always work as it keeps member and virtual methods pointers inside the class structure.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM