mark wrote:
The trick is to have C functions (global functions in C++ I guess) exported and to work in C++. C++ is geared up nicely for this. I have a version of my library that builds in C++ - I'll dig out the source code later if I get a chance.
That would be nice. In the meantime I have read some source code and the comp.lang.c++ FAQ. Basically it seems to me that there are two ways to reuse C++ libraries/header/cpp files:
<now I'll start jabbering, as I don't fully understand the following ;) >
Wrap it up with CPPExtern of GEM or something similar, maybe more sophisticated - and code in pure C++ yourself, with OO and all that bells and whistles.
Leave out the _real_ object orientation and write the main external code in C++, but not using a lot of the C++ features. I think, that's what Yves did in his stksitar adaption of Perry Cooks C++(!)-library STK. Reading through "stksitar~.cc" all this looks a lot like your typical C-external code, except usage of a sitar class which comes out of a C++-class defined in sitar.h (by P.Cook?!) Later on the setup function "stksitar_tilde_setup" is defined as: extern "C" void stksitar_tilde_setup(void) So obviously this function needs special treatment, whereas the others work without the extern declaration.
Why does 2) work? Can I just code right away in C++, and then just declare the _setup function as 'extern "C"' and all is well? I don't think so, but where is this the right, or the convenient way to go?
Frank Barknecht barknecht@dradio-online.de -= www.dradio.de =- DeutschlandRadio-Online * Redaktion Köln tel 0221 - 345 1471 * fax 0221 - 345 1480
- Leave out the _real_ object orientation and write the main external code
in C++, but not using a lot of the C++ features. I think, that's what
Yves [snip]
extern "C" void stksitar_tilde_setup(void) So obviously this function needs special treatment, whereas the others work without the extern declaration. Why does 2) work? Can I just code right away in C++, and then just declare the _setup function as 'extern "C"' and all is well? I don't think so, but where is this the right, or the convenient way to go?
The basic problem is with what is called "name mangling" - the compiler does stuff to the name symbols to make the job of the linker straight forward. In C++ this mangling is quite bad 'cos it puts the class name in as well. In C its fairly inocuous. Basically you need to declare the functions that PD is going to call outside of classes with extern "C" - you can use all of C++'s features without any problems (it all compiles down to machine code anyway) and you can call classes without any problem from within these funcitons.
Interestingly the PD external code are very object oriented - class methods in C++ have a hidden pointer to the class as the first argument - in PD this is explicit. It would be a very small leap to convert PD externs into C++ classes - all most of them would need would be the first arg removing and "x->" changing to "this.". Pointers to function are messier in C++ but you can get round it with macros. I don't know if Miller has considered it but converting PD to C++ might make writing externals a bit more pleasent.
As an point of interest most of C++ can be implmented as a pre-process to C.
My girlfriend is being induced tomorrow so I will dig the source code out at the start of next week I guess all things being well..
mark
Frank Barknecht wrote:
Basically it seems to me that there are two ways to reuse C++ libraries/header/cpp files:
<now I'll start jabbering, as I don't fully understand the following ;) >
- Wrap it up with CPPExtern of GEM or something similar, maybe more sophisticated - and code in pure C++ yourself, with OO and all that bells and whistles.
Yes, you can always do this.
- Leave out the _real_ object orientation and write the main external code in C++, but not using a lot of the C++ features. I think, that's what Yves did in his stksitar adaption of Perry Cooks C++(!)-library STK. Reading through "stksitar~.cc" all this looks a lot like your typical C-external code, except usage of a sitar class which comes out of a C++-class defined in sitar.h (by P.Cook?!) Later on the setup function "stksitar_tilde_setup" is defined as: extern "C" void stksitar_tilde_setup(void) So obviously this function needs special treatment, whereas the others work without the extern declaration.
Perry Cook's toolkit is a good example of using an existing C++ library in C. In generaly, you don't have to leave out the "real object orientation" in this case, although maybe I'm not sure what you mean by that. Certainly if your extern is a C++ file compiled by a C++ compiler, you can use any C++ features you wish. (Yes, if sitar.h is part of the STK, then it was written by Perry Cook without regards for later being used in a C application). The problem is not one of not being able to use all the features of C++; rather it is more a design problem of how to interface classes written in C++, to PD's own object system which is implemented in C.
As someone else explained, what the "extern "C"" does is to arrange that the function will show up in the object file's symbol table with a name that is compatible with the symbol name produced by a C compiler. Without this, the C++ compiler will generate a name the encodes not only the function name, but the arguments and their types, and I think the return type as well. The reason for this, is that unlike in C, the C++ functions "void foo(int)" and "void foo(float)", for example, are actually two different functions. They might (as an example) be actually named in the symbol table as "v$foo$i" and "v$foo$f". (I just made that particular encoding scheme up, so you get the idea - it could really use any similar method.)
In the case of a PD extern, it is really only the setup function that is called *by-name* from C. The setup function in turn calls various PD functions to arrange the other functions to be called at appropriate times. I haven't looked at the PD STK code lately, but most likely the reason that the other functions, like the "new" function are not declared as "extern C", is because they are only called from PD through pointers (as arranged by the setup function). Hence in the case of the other functions, they are not called through two different compiled/linked modules (hence the linker is not involved), so that is why even though the "new" function (the pd-new and not "new" in the C++ sense) is in fact called through the PD code, there is no need for the "extern "C"" declaration.
Now, that is not the only consideration. Any function that is called from C code can not be a C++ class member function. That is because C++ member functions invisibly take a first argument which is a pointer to the class that they are being called for. And naturally, the existing C code will not pass the "this" pointer". This is the real design problem usually, when calling a C++ library from C code. Talking in general terms now, and not about PD, a typical idiom is something like this:
extern "C" void CFooBar ( <args> ) { Foo *foo = FindObjectToCall ( <args> ); foo->Bar ( <args> ); }
or class Foo { public: static Foo* FindObjectToCall ( <args> ) void Bar( <args> ) };
extern "C" void CFooBar ( <args> ) { Foo *foo = Foo::FindObjectToCall ( <args> ); foo->Bar ( <args> ); }
Another issue with using C++ code with PD, is that of memory allocation. PD has defined its own allocation routines (what is it, "pd_malloc" or something like that?). So if you allocate your C++ objects using the "new" operator, you won't pass through the PD-specific memory allocation. My guess is that this is not a problem, however. I think that the PD allocation routines simply use the C library's "malloc", in which case there would be no conflict.
Well, I'm gonna have to stop now before writing a whole book. Hope this helps!
Larry Troxler
Why does 2) work? Can I just code right away in C++, and then just declare the _setup function as 'extern "C"' and all is well? I don't think so, but where is this the right, or the convenient way to go?
Hi,
Larry Troxler hat gesagt: // Larry Troxler wrote:
In generaly, you don't have to leave out the "real object orientation" in this case, although maybe I'm not sure what you mean by that.
[Larry starts his book here...]
Well, I'm gonna have to stop now before writing a whole book. Hope this helps!
My answer comes late, but actually your (and the others) comments were so interesting and gave me great stuff to learn, that I started coding immediatly and I'm now halfway through the port of rx-saturno to an external. I does sound, although very faint, but I can scale that.
I will publish, when done.
Thanks and bye, [...until the sure to follow next questions]