tags:

views:

91

answers:

1

Hello. I've been reading questions on Stack Overflow for a few weeks now... this'll be my first question.

So recently I've looked into making C access/manipulate a C++ class. I understand that ideally one shouldn't compile components in C and C++ separately under normal circumstances, but this isn't an option at the moment.

I looked into 3 Tutorials regarding being able to port/use a C++ in C. They are:

"A Guide to C++ and C Interoperability" on DevX

"Mixing C and C++ Code in the Same Program" article on Sun's site.

"[32] How to mix C and C++" on Parashift

First, what I already know:

  • You must use extern "C" to avoid C++ function name mangling.

  • You need callback prototypes that are C-compatible.

  • G++ must compile the C++ into .o files, GCC compiles the C-specific code into .o files, then link both after.

As a result, the project I have is made of 4 files:

  1. foo.h, header that'll list all prototypes that C/C++ will see (classes invisible to C of course)
  2. foo.cpp containing the Foo class, and a set of C-compatible callback functions to invoke the class and methods.
  3. fooWrap.c a set of C-specific wrappers that reference the callback functions in foo.cpp.
  4. main.c the test method.

Here's the code I typed up, then my questions:

FOO.H

// Header File foo.h
#ifndef FOO_H
#define FOO_H

//Content set inside this #ifdef will be unseen by C compilers
    #ifdef __cplusplus
        class Foo
        {
        public:
           void setBar(int);
           void printBar();
        private:
            int bar;
        };
    #endif
//end of C++-only visible components.

    #ifdef __cplusplus
    extern "C" {
    #endif

    //Stuff made to be seen by C compilers only. fooWrap.c has definitions.
    #if defined(__STDC__) && !defined(__cplusplus)
        typedef struct Foo Foo;

        //C-wrappers for C++ callback functions.
        Foo * c_NewFoo();
        void c_SetFooBar( Foo *, int);
        void c_PrintFooBar( Foo *);    
    #endif

    //These are the functions C++ AND C can both use...
    Foo * newFoo();                //allocates the memory for Foo class, pass address back.
    void setFooBar( Foo * , int ); //set internal contents of Foo object.
    void printFooBar ( Foo * );    //print internal contents of Foo object.

    #ifdef __cplusplus
    }
    #endif

#endif /*FOO_H*/

TEST.C

#include "foo.h"

// test.c test file for wrappers that manipulate C++ objects.

main()
{

//looks very C++ like... this makes C-Programmers cringe doesn't it?
Foo * cfoo = c_NewFoo();
Foo * cppfoo = newFoo();

//using the C-specific wrappers.
c_SetFooBar(cfoo,31415);
c_PrintFooBar(cfoo);

//using the C/C++ callback functions to Foo objects.
setFooBar(cppfoo,9001);
printFooBar(cppfoo);

}

So I split the definitions up into the 4 files as I mentioned before... and it compiles fine. But here's what I don't quite get.

Why do the sun and parashift articles suggest to create C-Wrappers whose only code is to pass it's arguments onto C/C++ compatible functions who then call C++ specific code?

i.e.

//in Stuff.cpp
void CallCppStuff () { /* c++ stuff */ }

//in wrapStuff.c
wrapCppStuff() { CallCppStuff() }

As you can see from my test.c file... I'm able to call up either set of calls without a problem (as far as I can tell). Are the c_ wrappers needless overhead, or am I missing the whole point of them altogether? My only guess has something to do with pointer addressing schemes of C/C++... but I'm not sure.

Also, I imagine there are more issues beyond just this... but those 3 sites are all I could find specific to this problem. So if there are any other glaring oversights on my part, I'd appreciate their mentioning.

Thanks in advance for any help/advice, CX

+6  A: 

If you have a series of functions that are not object-orientated or in a namespace, there's no need to wrap them again. Your c_ series of functions are redundant.

Any C++ function that is extern C, has global (i.e., not namespace/static member) linkage, and only takes C-compat datatypes (normally we use opaque pointers like you have), then it doesn't need to be wrapped. That is the wrapping function. C++ uses member functions directly and doesn't need to use them, and they certainly don't need to be duped.

DeadMG
Thanks. It's as I figured... but again I was a bit confused as the Sun and Parashift articles made the redundant functions.
CodeXCDM
Also, you forgot a DeleteFoo function.
DeadMG