I have been following this guide on how to call a member function of a C++ object from C. As I've understood it, the C code should interpret the class as a struct of the same name, and whenever it wants to call a function through an object of this class it should use an intermediate callback function. The header looks like this:
// CInterface.h
#ifdef __cplusplus
...
class CInterface
{
public:
...
void OnMessage(U8* bytes); // I want to call this function from C.
private:
...
};
#else
typedef
struct CInterface
CInterface;
#endif
#ifdef __cplusplus
extern "C" {
#endif
#if defined(__STDC__) || defined(__cplusplus)
//extern void c_function(CInterface*); /* ANSI C prototypes (shouldn't be needed) */
extern CInterface* cpp_callback_function(CInterface* self, unsigned char * bytes);
#else
//extern void c_function(); /* K&R style (shouldn't be needed) */
extern CInterface* cpp_callback_function(unsigned char * bytes);
#endif
#ifdef __cplusplus
}
#endif
The C code that fails right now looks like this:
// main.c
#include "CInterface.h"
int main(int argc, char* argv[])
{
void* ptr;
int *i = ptr; // Code that only compiles with a C compiler
CInterface cinterface; // This should declare a struct
}
The error is: error C2079: 'cinterface' uses undefined struct 'CInterface'.
It sounds like the header is being read as c++ code as the struct is not defined, but main.c is being compiled by C according to Visual Studio (I also double checked this by adding some C-specific code). However, if I add parentheses like this:
CInterface cinterface();
the code compiles which makes no sense to me as it now is an object which shouldn't work in C.
The callback function is implemented in a third file, CInterface.cpp, which acts as the "intermediate".
So the question is how I solve this error message, or if I got the entire approach wrong. It's the first time I mix C/C++ code and I'm relatively new to both languages.
In your example CInterface is only defined for C++. If you take a closer look at the example you linked you'll notice that this is also the case for the Fred class.
From C you can only pass around pointers to CInterface and you have to rely on C++ functions defined with C linkage to actually manipulate CInterface instances.
Otherwise you could define a struct as a means to pass around data between C and C++. Just ensure its definition is declared as extern "C" when used from C++:
#ifdef __cplusplus
extern "C" {
#endif
struct CandCPlusPlus {
// ...
};
#ifdef __cplusplus
}
#endif
Related
I am currently working on a mixed C and C++ project. Lately it happened that external library I have no control over added an inline function containing register keyword to header. For simplicity let's assume header looks like this:
// external_header.h
inline int do_stuff() {
register int res = 1;
return res;
}
// some functions declarations without name mangling
And let's assume this is my code (as usless as it is):
// my_code.cpp
#ifdef __cplusplus
extern "C"{
#endif
#include <external_header.h>
#ifdef __cplusplus
}
#endif
int main(inc argc, char** argv) {
return 0;
}
Compiling my_code.cpp with C++17 switch gives error like this:
error: ISO C++17 does not allow ‘register’ storage class specifier [-Werror=register]
Can there be anything done to work around this error? If so, what is to be done?
Using compiler options, you can disable the -Werror flag for this warning only:
-Werror -Wno-error=register
Or you can disable this warning altogether:
-Wno-register
Or within the code you could use preprocessor macro to remove this keyword. Note that replacing keywords (even unused ones like register) is Undefined Behaviour.
#ifdef __cplusplus
extern "C"{
#endif
#define register
#include <external_header.h>
#undef register
#ifdef __cplusplus
}
#endif
If the C header isn't written in the common subset of C and C++ - and in your case it isn't - then you cannot include it in C++.
If you have no control over the header, then what you can do instead is write a header of your own that is written in valid C++. In order to use the problematic function, you can write a non-inline wrapper function in C where the non C++ header can be included, and delegate to the inline function.
Example:
// external_header.hpp
// ... imagine header guard of your choice here ...
extern "C"{
int do_stuff_cpp(); // this is valid C++
// some functions declarations without name mangling
}
// external_header_cpp.c
#include "external_header.h"
int do_stuff_cpp()
{
return do_stuff();
}
I have a C++ header and cpp files like abc.hpp and abc.cpp which has 2 classes that is class A and class B, am trying to write a C layer containing different methods which calls the C++ layer methods, to call the C++ methods I need to create the instance of Class A and then use this instance to call C++ methods, I have created a C layer but tried different ways to create an instance of class B but it was not possible.
This is ABC.hpp
#ifndef ABC_HPP
#define ABC_HPP
namespace utils {
using std::vector;
using std::string;
class __declspec(dllexport) A
{
protected:
string m_color;
string m_type;
public:
A() {
// TODO: Complete the constructor by intializing everything
m_color = "";
m_type = "";
}
void setColor(string icolor){m_color = icolor;}
void setType(string itype){m_type = itype;}
string getColor(){return m_color;}
string getType() {return m_type;}
virtual ~A() {};
};
class __declspec(dllexport) B
{
// Member Variables
protected:
string file_name;
string place_name;
public:
void setFilename(fname){file_name = fname;}
void setPlaceName(pname){place_name = pname;}
string getFilename(){return file_name;}
string getplaceName() {return place_name;}
void getRes();
};
};
#endif
Similarly we have ABC.cpp
Next I create the C layer xyz_c.h
#ifndef XYZ_H
#define XYZ_H
#ifdef __cplusplus
extern "C"
{
#endif
__declspec(dllexport) int getPlaceNames(char** oNames);
#ifdef __cplusplus
}
#endif
#endif
Next I create XYZ.cpp
#include "XYZ.h"
#include "ABC.h"
#ifdef __cplusplus
extern "C" {
#endif
int getResults(char** oNames)
{
//here I need to create the instance of B to Call C++ layer getRes()
}
#ifdef __cplusplus
}
#endif
You cannot. C++ was designed to allow it to use the whole set of C legacy code already written, but the other side is not possible... simply because when C was designed there was no C++ available, and C doesn't have constructs as C++ has to be able to link routines written in C.
This means that if you want to combine C and C++ code, the program must be linked as a C++ program (built as) and you can include every routine you want (you can compile individual modules as C modules) but you have to access them from the C++ code including a extern "C" linkage statement in the C++ code (and never the reverse)
C++ has a naming convention for methods and c++ functions that includes information in the name about the types and number of parameters to allow for overloading and to include the object instance in the parameter list. This is simply unknown for a C compiler, so you cannot easily guess the name that the linker uses for something so simple as a void f(void) function (it can be something like 1f4void (yes, starting with a digit) making it impossible to be accessed from C (as C identifiers must start with a letter or underscore). If you declare f as extern "C" f(void), then you can call it from C modules, and it can even be implemented in C (and compiled in c), and the linker will know it as _f (or f is in use today also, depending on the compiler)
You can even write the int main(int argc, char **argv) funtion as a C function, but when you link it, you will need to use the C++ linker, if you want your program to include C++ code.
The proper way to do this is as follows. In your "C" interface code, you should have functions matching the c++ interface with the addition of a void* parameter. This parameter will be used to hold the instance for future usage by XYZ.
SO I would add a abc.c, with definitions as:
void setFilename(void* b, char *fname){
((B*)b)->setFilename(fname);
};
of course you will need to define also creator function such as:
void* CreateB(){
return (void*)new B();
}
I am trying to compile an application involving both C and C++ files. With one particular header I face issues. The file in question (a C++ header file), would look something like this:
#ifndef TASK_H
#define TASK_H
#include "MyCCPObject.h"
int foo1(int);
int foo2(int);
int fooObject(MyCCPObject myCppObject); // Function involves a Class "MyCCPObject" type
#ifdef __cplusplus
extern "C" {
#endif
int foo3(void); // Function called in a C file
#ifdef __cplusplus
}
#endif
#endif //TASK_H
I have a function fooObject() which has a MyCCPObject class type as a parameter. Also, one of the functions, foo3() would be called from a C file.
When the C compiler, compiles this header, I get the following error: "error: #20:identifier "class" is undefined". To avoid this, I had to:
Place the fooObject() declaration within compiler guards:
#ifdef __cplusplus
int fooObject(MyCCPObject myCppObject);
#endif
Place compiler guards also in the class declaration in the header file MyCCPObject.h:
#ifdef __cplusplus
class MyCCPObject
{
public:
MyCCPObject(uint32_t val);
private:
uint32_t value;
};
#endif
Note: The MyCCPObject would not be called in any C file.
So, what would be a better approach, when I have a C++ header file, which involves:
Function would involves a class object
A extern call to a C file
Use separate headers for your C and C++ code.
Move the foo3 declaration (including the __cplusplus guards) inside a separate header. Let's call it Foo3.h
You now have the following files:
Task.h - contains the declarations for foo1 and foo2, fooObject and includes MyCCPObject.h
Foo3.h - contains the declarations for foo3
Task.cpp - includes Task.h and Foo3.h and provides definitions for foo1, foo2 and foo3
App.c - includes Foo3.h and uses foo3
From your build system (make, cmake etc.), when building the C++ library, add the files Task.h, Foo3.h, Task.cpp (and the other files related to MyCCPObject)
When building the C application, add only Foo3.h and App.c. That way, the other headers (which contain C++ code) will not be compiled and hence not give out any errors.
The makers of C++ wrote a FAQ which is also giving some guidance on how to mix C and C++. They are also looking at the possibility to use C++ objects from C code.
Option 1: If you just want the C compiler to be able to parse your task.h header file, then you could hide the C++ parts my using #ifdef __cplusplus:
#ifndef TASK_H
#define TASK_H
#ifdef __cplusplus
#include "MyCCPObject.h"
int foo1(int);
int foo2(int);
int fooObject(MyCCPObject myCppObject); // Function involves a Class "MyCCPObject" type
extern "C" {
#endif
int foo3(void); // Function called in a C file
#ifdef __cplusplus
}
#endif
#endif //TASK_H
Option 2: If you want to make the fooObject function accessible from C, then you can change MyCppObject.h to provide the full class information to C++ and only a minimal typedef for C. The typedef makes sure that C understands just the class name MyCCPObject without writing class or struct before it.
#ifdef __cplusplus
class MyCCPObject
{
public:
MyCCPObject(uint32_t val);
private:
uint32_t value;
};
#else
typedef struct MyCCPObject MyCCPObject;
#endif
and task.h to
#ifndef TASK_H
#define TASK_H
#include "MyCCPObject.h"
int foo1(int);
int foo2(int);
#ifdef __cplusplus
extern "C" {
#endif
int fooObject(MyCCPObject *myCppObject); // Function involves a Class "MyCCPObject" type
int foo3(void); // Function called in a C file
#ifdef __cplusplus
}
#endif
#endif //TASK_H
Please note that I needed to change the signature of fooObject to take a pointer to the object as the C code does not see the complete class and does not know the size of the object.
I'm writing a small Wrapper API so i can call some C++ code (classes/ functions) from C.
I got the problem, that one of my C++ functions is initialised in my wrapper header with a "shared_ptr".
ClassName *ClassName _new(std::shared_ptr<Lib::Instance> p_Instance);
So as you can see, the wrapper file is infested with C++ style. This is bad because the Wrapper file should be readable by C AND C++.
This is my Wrapper.h file:
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
typedef struct ClassName ClassName;
ClassName *ClassName_new(std::shared_ptr<Lib::Instance> p_Instance);
void ClassName_setValue(ClassName* t, double p_value);
void ClassName_delete(ClassName* t);
#ifdef __cplusplus
}
#endif /* __cplusplus */
and this is my Wrapper.cpp file:
#include "Wrapper.h"
#include "ClassName.h"
extern "C"{
ClassName* ClassName_new(std::shared_ptr<Lib::Instance> p_Instance){
return new ClassName(p_Instance);
}
void ClassName_setValue(ClassName* t, double p_value){
t->setValue(p_value);
}
void ClassName_delete(ClassName* t){
delete t;
}
}
And this is the part of my main .cpp file
Header:
class ClassName: public Lib::Util::Task {
public:
ClassName(std::shared_ptr<Lib::Instance> p_Instance);
virtual ~ClassName();
void setValue(double p_value);
...
.Cpp:
ClassName::ClassName(std::shared_ptr<Lib::Instance> p_Instance) ...
...
void ClassName::setValue(double p_value){
doSomething()
}
...
I'm not allowed to change my structure of the main c++ file where I am using the ClassName(std::shared_ptr<Lib::Instance> p_Instance);
Do you have any ideas how I can fix this problem?
Maybe writing a second Wrapper?
Edit:
Here is the error given by the Terminal:
Wrapper.h:21:45: error: expected ‘)’ before ‘:’ token
ClassName *ClassName_new(std::shared_ptr<Lib::Instance> p_Instance);
^
The function cannot be used in C, so you can use the pre-processor to remove the declaration just like you used with extern "C":
// Wrapper.h
#ifdef __cplusplus
ClassName *ClassName_new(std::shared_ptr<Lib::Instance> p_Instance);
#endif
Although, it this wrapper isn't supposed to be used in C++ by anything other than Wrapper.cpp, then moving the declaration into Wrapper.cpp might be a better option.
If you need a way of invoking ClassName_new from C, I would suggest steering away from shared pointer. But you could make it work with an opaque wrapper:
// Wrapper.h
struct opaque_wrapper* make_instance(void);
void release_instance(struct opaque_wrapper*);
ClassName *ClassName_new(struct opaque_wrapper*);
// Wrapper.cpp
struct opaque_wrapper {
std::shared_ptr<Lib::Instance> p_Instance;
};
opaque_wrapper* make_instance() {
return new opaque_wrapper{std::make_shared<Lib::Instance>()};
}
void release_instance(struct opaque_wrapper* instance) {
delete instance;
}
ClassName *ClassName_new(struct opaque_wrapper* instance) {
return ClassName_new(instance->p_Instance);
}
I would suggest embedding the reference counter into the object and use boost::intrusive_ptr with it. This way you can pass a plain pointer to C functions and those C functions can still manage the object's lifetime directly calling C-style addref/release on it.
You cannot use classes from C++ in C.
You can define function prototypes of C calling convention C functions, to be used from C++ with the following wrapper code around in the header file:
#ifdef __cplusplus
extern "C" {
#endif
/* put here C calling convention C functions */
#ifdef __cplusplus
};
#endif
and you'll get a definitions file that can be used either in C or in C++. __cplusplus is a macro defined by the c++ compiler when compiling C++ code, and it introduces the extern "C" { environment to support C functions. Those functions follow the C style calling conventions (you cannot overload them, you cannot use method definitions or define classes in there)
I am trying to access a C++ class and call its method from a .c file.
I google this topic and find this http://developers.sun.com/solaris/articles/mixing.html
It says:
You can write extern "C" functions in C++ that access class M objects and call them from C code.
Here is a C++ function designed to call the member function foo:
extern "C" int call_M_foo(M* m, int i) { return m->foo(i); }
My question is where do I put the about line? In my C++ .h file? Or C .h file?
And it goes on and says:
Here is an example of C code that uses class M:
struct M; // you can supply only an incomplete declaration
int call_M_foo(struct M*, int); // declare the wrapper function
int f(struct M* p, int j) // now you can call M::foo
{
return call_M_foo(p, j);
}
But how/where do I create the class M in my C file?
And where do I put the above code? C .h file? C++ .h file? Or C .c file?
Thank you.
Thank you for GMan's detailed answer.
I did follow your suggestion. But I get compile error in my .c file.
main.c:33:
./some_class.h:24: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘attribute’ before ‘’ token
./some_class.h:25: error: expected ‘)’ before ‘’ token
./some_class.h:26: error: expected ‘)’ before ‘*’ token
And here are my some_class.h line 24-26:
#ifdef __cplusplus
class M {
public:
M();
virtual ~M();
void method1(char* name, char* msg);
};
extern "C" {
#else
struct M;
#endif
/* access functions line 24-26 are here*/
M* M_new(void);
void M_delete(M*);
void M_method1(M*, char*, char*);
#ifdef __cplusplus
}
#endif
For some reason, my C compiler does not like extern "C" in GMan's original some_test.h. So I have to modify to above. It seems like the C compiler does not like/understand the struct M; line.
Any idea will be much appreciated.
Your header file, which is shared between your C and C++ code:
#ifdef __cplusplus // only actually define the class if this is C++
class some_class
{
public:
int some_method(float);
};
#else
// C doesn't know about classes, just say it's a struct
typedef struct some_class some_class;
#endif
// access functions
#ifdef __cplusplus
#define EXPORT_C extern "C"
#else
#define EXPORT_C
#endif
EXPORT_C some_class* some_class_new(void);
EXPORT_C void some_class_delete(some_class*);
EXPORT_C int some_class_some_method(some_class*, float);
Then your source file:
#include "some_foo.h"
int some_class::some_method(float f)
{
return static_cast<int>(f);
}
// access functions
EXPORT_C some_class* some_class_new(void)
{
return new some_class();
}
EXPORT_C void some_class_delete(some_class* this)
{
delete this;
}
EXPORT_C int some_class_some_method(some_class* this, float f)
{
return this->some_method(f);
}
Now compile that source, and link to it. Your C source would be something like:
#include "some_class.h"
some_class* myInstance = some_class_new();
int i = some_class_some_method(myInstance, 10.0f);
some_class_delete(myInstance);
If you're serious about mixing C and C++, you'll want macro's.
Here are some sample macro's that would make this much easier:
// in something like c_export.h
// extern "C" macro
#ifdef __cplusplus
#define EXPORT_C extern "C"
#else
#define EXPORT_C
#endif
// new
#define EXPORT_C_CLASS_NEW(classname) EXPORT_C \
classname * classname##_new(void)
#define EXPORT_C_CLASS_NEW_DEFINE(classname) \
EXPORT_C_CLASS_NEW(classname) \
{ return new classname (); }
// repeat as much as you want. allows passing parameters to the constructor
#define EXPORT_C_CLASS_NEW_1(classname, param1) EXPORT_C \
classname * classname##_new( param1 p1)
#define EXPORT_C_CLASS_NEW_1_DEFINE(classname, param1) \
EXPORT_C_CLASS_NEW_1(classname, param1) \
{ return new classname (p1); }
// delete
#define EXPORT_C_CLASS_DELETE(classname) EXPORT_C \
void classname##_delete( classname * this)
#define EXPORT_C_CLASS_DELETE_DEFINE(classname) \
EXPORT_C_CLASS_DELETE(classname) \
{ delete this; }
// functions
#define EXPORT_C_CLASS_METHOD(classname, methodname, ret) EXPORT_C \
ret classname##_##methodname##( classname * this)
#define EXPORT_C_CLASS_METHOD_DEFINE(classname, methodname, ret) \
EXPORT_C_CLASS_METHOD(classname, methodname, ret) \
{ return this->##methodname##(); }
// and repeat as necessary.
#define EXPORT_C_CLASS_METHOD_1(classname, methodname, ret, param1) EXPORT_C \
ret classname##_##methodname( classname * this, param1 p1)
#define EXPORT_C_CLASS_METHOD_1_DEFINE(classname, methodname, ret, param1) \
EXPORT_C_CLASS_METHOD_1(classname, methodname, ret, param1) \
{ return this->##methodname##(p1); }
And so on. Our header/source becomes:
// header
#include "c_export.h" // utility macros
#ifdef __cplusplus // only actually define the class if this is C++
class some_class
{
public:
int some_method(float);
};
#else
// C doesn't know about classes, just say it's a struct
typedef struct some_class some_class;
#endif
// access functions
EXPORT_C_CLASS_NEW(some_class);
EXPORT_C_CLASS_DELETE(some_class);
EXPORT_C_CLASS_METHOD_1(some_class, some_method, int, float);
// source
#include "some_foo.h"
int some_class::some_method(float f)
{
return static_cast<int>(f);
}
// access functions
EXPORT_C_CLASS_NEW_DEFINE(some_class);
EXPORT_C_CLASS_DELETE_DEFINE(some_class);
EXPORT_C_CLASS_METHOD_1_DEFINE(some_class, some_method, int, float);
And that's much more concise. It could be made simpler (possibly) with variadic macro's, but that's non-standard and I leave that to you. :] Also, you can make macro's for normal non-member functions.
Note that C does not know what references are. If you want to bind to a reference, your best bet is probably just to write the export definition manually. (But I'll think about it, maybe we can get it automatically).
Imagine our some_class took the float by (non-const)reference (for whatever reason). We'd define the function like so:
// header
// pass by pointer! v
EXPORT_C_CLASS_METHOD_1(some_class, some_method, int, float*) ;
// source
EXPORT_C_CLASS_METHOD_1(some_class, some_method, int, float*)
{
// dereference pointer; now can be used as reference
return this->some_method(*p1);
}
And there we go. C would interface with references with pointers instead:
// c source, if some_method took a reference:
float f = 10.0f;
int i = some_class_some_method(myInstance, &f);
And we pass f "by reference".
You need to split it among the C++ header and implementation files.
foo.h:
extern "C" int call_M_foo(M* m, int i);
foo.cc:
extern "C" int call_M_foo(M* m, int i) {
return m->foo(i);
}
To create the object of type M, you would need a similar function:
foo.h:
struct M;
extern "C" M* create_M();
foo.cc:
extern "C" M* create_M() {
return new M;
}
You have several questions combined here so I will answer them individually.
My question is where do I put the about line? In my c++ .h file? or c .h file?
The extern "C" line goes in the C++ file. It essentially tells the compiler to
limit everything whithin the extern "C" block to the C subset of C++, and to
export functions declared in this area accordingly.
But how/where do I create the class M in my c file?
You can't. C does not have the concept of classes, and there's absolutely no
way to instantiate a class directly. You essentially have to export a C function
in your C++ file which creates the class and returns it as a pointer. Then you
can pass that pointer around your C application. You can't actually modify the
class directly in your C application, because C does not support classes, and
your C++ compiler may insert "hidden" variables for bookkeeping inside the
actual declaration of the class.
And where do I put the above code?
The piece of code that uses a structure pointer goes in the C file. You are
forced to use a structure pointer because C does not support classes at all.
You can put function calls using that function anywhere in a C implementation
file, just like normal C function calls.
All the information you need is in the link you provide. You just need to understand that there needs to be a strict separation between C and C++ code.
C++ code can call any C code.
C code usually cannot call any C++ code.
C functions can be implemented by C++ code.
The key part to understand is that the C and C++ compilers mangle function names when making object files in different ways, so they would normally not be able to interoperate (at link time), except that C++ can be prompted to know the difference by using extern "C"
The prototype:
void f(int); might be mangled by a C compiler to: _f, but a C++ compiler might choose a very different name eg f_int, and so the linker would not know they are supposed to be the same.
However:
extern "C" void f(int);
would be mangled by a C++ compiler to _f, but a C compiler would choke on the extern "C". To avoid this you should used something like this:
#ifdef __cplusplus
extern "C" {
#endif
void f(int);
#ifdef __cplusplus
} /* closing brace for extern "C" */
#endif
Now the whole of the above section can live in a .h file and is, as the sun.com article states, a mixed-language header.
This means that a .c or .cpp file can #include this header and code can call f();
and either a .c or .cpp file can #include this header and implement it:
void f()
{
}
Now the good bit is that a .cpp file can implement this to call any C++ code it likes.
Now to answer your specific questions:
The first code sample can only go in a .cpp file.
The second code sample can only go in a .c file.
Additionally class M must be declared and defined in C++ files only.
The site you have linked to has the answer already:
You can declare function print in a
header file that is shared by C and
C++ code:
#ifdef __cplusplus extern "C"
#endif int print(int i, double d);
You can declare at most one function
of an overloaded set as extern "C"
Here is the example C header for the
wrapper functions:
int g_int(int);
double g_double(double);
Basically, there can be a header shared between the two that declares the function prototype, adding the extern "C" modifier if you are in C++ to ensure the function can be accessed in an object from C. You define the body of the function later on in the C++ code as usual, if necessary inside a class etc, and you use the function in C like normal.