In questions such as this, compatibility between C++ classes/structs and C structs is explained as possible as long as all members are of the same type, in the same order, and no virtual members are declared.
That's my problem. I have virtual methods, and I would very much like to keep them when manipulating the struct in C++.
Let's examine this toy example. It's meant to be a C and C++ compatible struct defined in a single header file.
mystr.h:
#ifdef __cplusplus
#include <string>
struct mystr_base {
virtual ~mystr_base() {}
virtual std::string toString() = 0;
};
#endif
#ifdef __cplusplus
extern "C" {
#endif
struct mystr
#ifdef __cplusplus
: public mystr_base
#endif
{
const char* data;
#ifdef __cplusplus
std::string toString() {
return std::string(data);
}
#endif
};
#ifdef __cplusplus
}
#endif
This may not be exactly pretty, but will do for the example. In a real scenario, the C and C++ variants may be in separate headers, with the C++ struct extending a POD struct. Regardless of implementation, the issue of alignment is still present.
With this example, if a C program was written that passes an instance of mystr to a C++ function, the vtable will interfere with the alignment:
test.h:
#include "mystr.h"
#ifdef __cplusplus
extern "C"
#endif
void mycxxfunc(struct mystr str);
test.cpp:
#include <stdio.h>
#include "test.h"
void mycxxfunc(mystr str) {
printf("mystr: %s\n", str.data);
}
main.c:
#include "test.h"
int main(int argc, char** argv) {
const char* testString = "abc123";
struct mystr str;
str.data = testString;
mycxxfunc(str);
}
$ g++ -c test.cpp && gcc main.c test.o
$ ./a.out
Segmentation fault (core dumped)
(presuming that this is because the C++ function is attempting to read data from beyond the end of the struct's allocated memory)
What's the best way to enable this C-C++ interoperability while still retaining the ability to use virtual functions in C++?
I do not recommend you to clutter your header file with #ifdefs.
The first thing you should do in this case if you want to retain some kind of virtualization and C compatibility at the same time is:
Make your C++ and C type an opaque pointer to the representation.
Put implementation details in a .cpp file.
An idea follows.
Header file:
struct MyStrImpl;
struct MyStr {
MyStrImpl * impl;
};
extern "C" MyReturnType myFunction(MyStr myStr);
Implementation in .cpp file:
struct MyCppString {
virtual ...
};
#ifdef __cplusplus
struct MyStrImpl : public MyCppString {
};
#else
struct MyStrImpl {
};
#endif
MyStr::MyStr() : impl{new MyStrImpl{}} {
}
This way you have a type that can be used from both C and C++.
Advantages:
No #ifdef in header file.
Compatible with C/C++ and consumable from both languages.
Disadvantages:
Lose overloading due to extern "C".
Must use a C-style interface (but can implement with C++-like with virtual functions interface in your .cpp file.
You cannot have both a C-compatible type and virtual functions in a header file at the same time without cluttering it with #ifdef, something that I do not recommend since it can be inconvenient if you need to refactor code.
Related
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've stumbled across some code that looks like this:
typedef struct SomeStruct
{
int foo;
void * bar;
#if defined(__cplusplus)
SomeStruct();
#endif
} SomeStruct;
It's in a header file that will be included by both .c and .cpp files. That seems to be at least technically a violation of the One-Definition-Rule. The obvious impact I see is that if one of these is ever declared in .c file, the constructor won't run. And unfortunately, someone seems to have used this as a pattern for the correct way to declare structs, and has declared a couple dozen structs just like it.
I'm trying to figure out how serious a problem this is. Beyond the constructor possibly not running, is there any other likely impact? The constructor is implemented in a .cpp file. I see pointers to structs allocted in a .c file (with malloc) that are passed to functions in the .cpp files. They appear to work correctly (compiled with gcc/g++ 4.6.2 for Suse Linux, if that matters), as far as I can tell. Would something break if virtual member functions were also added? Right now, none of these classes have anything in their cplusplus section other than the default constructor, as shown above.
It's not exactly a violation of the ODR. Informally, the C compiler see a POD type and the C++ compiler see a class in the global namespace which will become an entity with a mangled name. More importantly, the structure is only declared differently for C and C++ compilers, but it is only defined once in a C++ source file. Most likely there's some allocation and free functions in a C++ source file which expose the constructor/destructor to a C API. For example,
Header file
$ cat some_struct.h
#ifndef SOME_STRUCT_H
#define SOME_STRUCT_H
typedef struct SomeStruct {
int foo;
void *var;
#if defined(__cplusplus)
SomeStruct();
#endif
} SomeStruct;
#if defined(__cplusplus)
extern "C" {
#endif
SomeStruct *some_struct_malloc();
void some_struct_free(SomeStruct **);
#if defined(__cplusplus)
} // extern "C"
#endif
#endif // SOME_STRUCT_H
C++ source file
$ cat some_struct.cpp
#include "some_struct.h"
#include <cstddef>
SomeStruct::SomeStruct()
{
foo = 10;
var = NULL;
}
SomeStruct *some_struct_malloc() { return new SomeStruct; }
void some_struct_free(SomeStruct **pp)
{
if (*pp)
delete *pp;
*pp = NULL;
}
C source file:
$ cat main.c
#include "some_struct.h"
#include <stdio.h>
int main()
{
SomeStruct *p = some_struct_malloc();
printf("%d\n", p->foo);
}
I would say it is a bad style. But it works as a convenient way to expose a C++ library to a C API
I know this.
Calling C function from C++:
If my application was in C++ and I had to call functions from a library written in C. Then I would have used
//main.cpp
extern "C" void C_library_function(int x, int y);//prototype
C_library_function(2,4);// directly using it.
This wouldn't mangle the name C_library_function and linker would find the same name in its input *.lib files and problem is solved.
Calling C++ function from C???
But here I'm extending a large application which is written in C and I need to use a library which is written in C++. Name mangling of C++ is causing trouble here. Linker is complaining about the unresolved symbols. Well I cannot use C++ compiler over my C project because thats breaking lot of other stuff. What is the way out?
By the way I'm using MSVC
You need to create a C API for exposing the functionality of your C++ code. Basically, you will need to write C++ code that is declared extern "C" and that has a pure C API (not using classes, for example) that wraps the C++ library. Then you use the pure C wrapper library that you've created.
Your C API can optionally follow an object-oriented style, even though C is not object-oriented. Ex:
// *.h file
// ...
#ifdef __cplusplus
#define EXTERNC extern "C"
#else
#define EXTERNC
#endif
typedef void* mylibrary_mytype_t;
EXTERNC mylibrary_mytype_t mylibrary_mytype_init();
EXTERNC void mylibrary_mytype_destroy(mylibrary_mytype_t mytype);
EXTERNC void mylibrary_mytype_doit(mylibrary_mytype_t self, int param);
#undef EXTERNC
// ...
// *.cpp file
mylibrary_mytype_t mylibrary_mytype_init() {
return new MyType;
}
void mylibrary_mytype_destroy(mylibrary_mytype_t untyped_ptr) {
MyType* typed_ptr = static_cast<MyType*>(untyped_ptr);
delete typed_ptr;
}
void mylibrary_mytype_doit(mylibrary_mytype_t untyped_self, int param) {
MyType* typed_self = static_cast<MyType*>(untyped_self);
typed_self->doIt(param);
}
I would do it in the following way:
(If working with MSVC, ignore the GCC compilation commands)
Suppose that I have a C++ class named AAA, defined in files aaa.h, aaa.cpp, and that the class AAA has a method named sayHi(const char *name), that I want to enable for C code.
The C++ code of class AAA - Pure C++, I don't modify it:
aaa.h
#ifndef AAA_H
#define AAA_H
class AAA {
public:
AAA();
void sayHi(const char *name);
};
#endif
aaa.cpp
#include <iostream>
#include "aaa.h"
AAA::AAA() {
}
void AAA::sayHi(const char *name) {
std::cout << "Hi " << name << std::endl;
}
Compiling this class as regularly done for C++. This code "does not know" that it is going to be used by C code. Using the command:
g++ -fpic -shared aaa.cpp -o libaaa.so
Now, also in C++, creating a C connector:
Defining it in files aaa_c_connector.h, aaa_c_connector.cpp. This connector is going to define a C function, named AAA_sayHi(cosnt char *name), that will use an instance of AAA and will call its method:
aaa_c_connector.h
#ifndef AAA_C_CONNECTOR_H
#define AAA_C_CONNECTOR_H
#ifdef __cplusplus
extern "C" {
#endif
void AAA_sayHi(const char *name);
#ifdef __cplusplus
}
#endif
#endif
aaa_c_connector.cpp
#include <cstdlib>
#include "aaa_c_connector.h"
#include "aaa.h"
#ifdef __cplusplus
extern "C" {
#endif
// Inside this "extern C" block, I can implement functions in C++, which will externally
// appear as C functions (which means that the function IDs will be their names, unlike
// the regular C++ behavior, which allows defining multiple functions with the same name
// (overloading) and hence uses function signature hashing to enforce unique IDs),
static AAA *AAA_instance = NULL;
void lazyAAA() {
if (AAA_instance == NULL) {
AAA_instance = new AAA();
}
}
void AAA_sayHi(const char *name) {
lazyAAA();
AAA_instance->sayHi(name);
}
#ifdef __cplusplus
}
#endif
Compiling it, again, using a regular C++ compilation command:
g++ -fpic -shared aaa_c_connector.cpp -L. -laaa -o libaaa_c_connector.so
Now I have a shared library (libaaa_c_connector.so), that implements the C function AAA_sayHi(const char *name). I can now create a C main file and compile it all together:
main.c
#include "aaa_c_connector.h"
int main() {
AAA_sayHi("David");
AAA_sayHi("James");
return 0;
}
Compiling it using a C compilation command:
gcc main.c -L. -laaa_c_connector -o c_aaa
I will need to set LD_LIBRARY_PATH to contain $PWD, and if I run the executable ./c_aaa, I will get the output I expect:
Hi David
Hi James
EDIT:
On some linux distributions, -laaa and -lstdc++ may also be required for the last compilation command. Thanks to #AlaaM. for the attention
Assuming the C++ API is C-compatible (no classes, templates, etc.), you can wrap it in extern "C" { ... }, just as you did when going the other way.
If you want to expose objects and other cute C++ stuff, you'll have to write a wrapper API.
You will have to write a wrapper for C in C++ if you want to do this. C++ is backwards compatible, but C is not forwards compatible.
export your C++ functions as extern "C" (aka C style symbols), or use the .def file format to define undecorated export symbols for the C++ linker when it creates the C++ library, then the C linker should have no troubles reading it
#include <iostream>
//////////////
// C++ code //
//////////////
struct A
{
int i;
int j;
A() {i=1; j=2; std::cout << "class A created\n";}
void dump() {std::cout << "class A dumped: " << i << ":" << j << std::endl;}
~A() {std::cout << "class A destroyed\n";}
};
extern "C" {
// this is the C code interface to the class A
static void *createA (void)
{
// create a handle to the A class
return (void *)(new A);
}
static void dumpA (void *thisPtr)
{
// call A->dump ()
if (thisPtr != NULL) // I'm an anal retentive programmer
{
A *classPtr = static_cast<A *>(thisPtr);
classPtr->dump ();
}
}
static void *deleteA (void *thisPtr)
{
// destroy the A class
if (thisPtr != NULL)
{
delete (static_cast<A *>(thisPtr));
}
}
}
////////////////////////////////////
// this can be compiled as C code //
////////////////////////////////////
int main (int argc, char **argv)
{
void *handle = createA();
dumpA (handle);
deleteA (handle);
return 0;
}
You can prefix the function declaration with extern “C” keyword, e.g.
extern “C” int Mycppfunction()
{
// Code goes here
return 0;
}
For more examples you can search more on Google about “extern” keyword. You need to do few more things, but it's not difficult you'll get lots of examples from Google.
I'm trying to wrap a C library in C++, to make it a modern, high level and idiomatic C++ library. What I want to do, is to make the C objects completely opaque and/or directly unavailable from the C++ code and wrap/replace them with higher-level alternatives.
The problem I'm facing with is simple: I want to include the C header only to the C++ source, so that the C++ header when included won't include the C header's declarations as well, that is, it won't pollute the global namespace.
But it looks like the correct separation of the header and source files does not allow me to do that. Here is a very much dummified version of my problem, the comments will tell you the rest:
my_header.h:
typedef enum
{
my_Consts_ALPHA = /* some special value */,
my_Consts_BETA = /* other special value */,
} my_Consts;
typedef struct
{
// members...
} my_Type;
void
my_Type_method(my_Type *const,
my_Enum);
my_header.hpp:
namespace my
{
enum class Consts; // <-- This header is missing the constant values of
// this enum, because its values are defined by
// the C header :(
class Type : public my_Type // <-- The super struct is coming from the
// C header, but I don't want to include
// that header here :(
{
public:
void
method(Consts constant);
};
}
my_source.cpp:
extern "C"
{
#include "my_header.h"
}
#include "my_header.hpp"
namespace my
{
enum class Consts
{
ALPHA = my_Consts_ALPHA,
BETA = my_Consts_BETA,
};
void
Type::method(Consts constant)
{
my_Type_method(static_cast<my_Type *const>(this),
static_cast<my_Consts>(constant));
}
}
So my questions are: am I missing something very obvious here? Is this even possible to achieve? Is there a trick that I'm not aware of?
In the comments of the question #AnalPhabet suggested sarcastically, that one should use #include of a C header inside a namespace. #n.m. confirmed, that it is actually a working solution, and now I tested it on my own setup, and fortunately it is working pretty fine.
(Although I have no idea, if this is implementation specific or not, but I tested on both g++ and clang++ and it is working.)
It does not solve the opaqueness problem, but at least it makes a bit harder to access to the raw C data directly as it is living in a separate namespace now, therefore the user can't accidentaly access, but willingly.
So, the my_header.hpp should look like this:
namespace my
{
extern "C"
{
#include "my_header.h"
}
enum class Consts
{
ALPHA = my_Consts_ALPHA,
BETA = my_Consts_BETA,
};
class Type : public my_Type
{
public:
void
method(Consts constant);
};
}
So wherever my_header.hpp is #include'd, the user can only access to the C values as follows:
my::my_Consts_ALPHA // The wrapped value is => my::Consts::ALPHA
my::my_Type // The wrapped value is => my::Type
my::my_Type_method(t,..) // The wrapped value is => t.method(..)
If the whole idea of writing high-level and idiomatic C++ wrapper is to bring safety, automatic memory management and convenient C++ types like std::sting, I would include C header into cpp file only.
Provide clean idiomatic C++ interface, and use C library only in the implementation.
Do not afraid to write a couple of utility functions that convert C data to C++ and back. If a C++ class should hold C-specific data, and it is not possible to replace it with C++ analog, use some type erasure technique to keep clean interface.
I wouldn't worry about performance due to such wrapping until I see it on top in a profiler log. In most cases it is not a bottleneck.
Again, splitting interface and implementation is usually a win.
UPDATE
Initially, I was thinking more about project specific C++ interface rather than universal C++ wrapper around C library.
Solution with extern "C" wrapped into a namespace looks correct to me (see §7.5 of C++11 standard). But, I've never seen this technique in the wild.
You can go further and add nested detail namespace to not pollute my namespace with C types. This trick is popular in header only libraries:
namespace my
{
namespace detail
{
extern "C"
{
#include "my_header.h"
}
}
enum class Consts
{
ALPHA = detail::my_Consts_ALPHA,
BETA = detail::my_Consts_BETA,
};
class Type : public detail::my_Type
{
public:
void
method(Consts constant);
};
}
Take into account that you can't make C functions completely opaque or wrap them to a single namespace when you link with static library. They have external linkage and know nothing about namespaces.
namespace A {
extern "C" void my_Type_method(my_Type *const, my_Enum);
}
namespace B {
extern "C" void my_Type_method(my_Type *const, my_Enum);
}
extern "C" void my_Type_method(my_Type *const, my_Enum);
Basically, all these declarations refer to the same C function. As C doesn't support namespaces and overloading, linker usually uses function names as unique identifiers (even argument types are ignored).
Anyway, this approach will help to avoid accidental access to C interface.
I'm not sure if it's language legal, but I think extern "C" is just there to unmangle functions, so as long as you keep them in the .cpp file you can get away with this.
This is a little profane, but it seems to work with gcc 4.3.5. It demonstrates that you can use C functions while also hiding them in a namespace.
I didn't bother with inheriting struct_t, but it should probably work. I have no idea if you can pull off the enum class.
foo.h
#ifndef foo_H
#define foo_H
typedef enum {
ALPHA,
BETA
} enum_t;
typedef struct
{
int i;
} struct_t;
void printit(struct_t print_me);
#endif // foo_H
foo.c
#include <stdio.h>
#include "foo.h"
void printit (struct_t print_me)
{
printf ("Hello World %d!\n", print_me.i);
}
bar.hpp
#ifndef bar_HPP
#define bar_HPP
namespace _foo {
// Don't need extern "C" since we're not using functions
#include "foo.h"
}
struct based_on_struct_t // : public _foo:struct_t // Do you really have to derive? It might be possible, but it's ugly
{
_foo::struct_t i;
double j;
based_on_struct_t (int _i, double _j) : j(_j) { i.i = _i; }
void print(void); // Gonna call printit, MUST be in .cpp
};
#endif // bar_HPP
bar.cpp
namespace _foo{
extern "C" {
#include "foo.h"
}
}
#include "bar.hpp"
#include <stdio.h>
void based_on_struct_t::print (void) {
// Call the old version...
printit(i);
// And do new crap
printf ("Goodbye World %d %f\n", i.i, j);
}
driver.cpp
#include "bar.hpp"
int main (void) {
based_on_struct_t B(10, .1);
B.print();
return 0;
}
Demo...
$ gcc foo.c -c -O3
$ g++ foo.o bar.cpp driver.cpp
$ ./a.out
Hello World 10!
Goodbye World 10 0.100000
$
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