Conditional C/C++ struct definitions - c++

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

Related

Using C++ struct with virtual members (i.e. non-POD) in C

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.

How not to pollute the global namespace with declarations of a C header?

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
$

C++ program using a C library headers is recognizing "this" as a keyword. Extern "C" error?

My C++ program needs to use an external C library.
Therefore, I'm using the
extern "C"
{
#include <library_header.h>
}
syntax for every module I need to use.
It worked fine until now.
A module is using the this name for some variables in one of its header file.
The C library itself is compiling fine because, from what I know, this has never been a keyword in C.
But despite my usage of the extern "C" syntax,
I'm getting errors from my C++ program when I include that header file.
If I rename every this in that C library header file with something like _this,
everything seems to work fine.
The question is:
Shouldn't the extern "C" syntax be enough for backward compatibility,
at least at syntax level, for an header file?
Is this an issue with the compiler?
Shouldn't the extern "C" syntax be enough for backward compatibility, at least at syntax level, for an header file? Is this an issue with the compiler?
No. Extern "C" is for linking - specifically the policy used for generated symbol names ("name mangling") and the calling convention (what assembly will be generated to call an API and stack parameter values) - not compilation.
The problem you have is not limited to the this keyword. In our current code base, we are porting some code to C++ and we have constructs like these:
struct Something {
char *value;
char class[20]; // <-- bad bad code!
};
This works fine in C code, but (like you) we are forced to rename to be able to compile as C++.
Strangely enough, many compilers don't forcibly disallow keyword redefinition through the preprocessor:
#include <iostream>
// temporary redefinition to compile code abusing the "this" keyword
#define cppThis this
#define this thisFunction
int this() {
return 1020;
}
int that() {
return this();
}
// put the C++ definition back so you can use it
#undef this
#define this cppThis
struct DumpThat {
int dump() {
std::cout << that();
}
DumpThat() {
this->dump();
}
};
int main ()
{
DumpThat dt;
}
So if you're up against a wall, that could let you compile a file written to C assumptions that you cannot change.
It will not--however--allow you to get a linker name of "this". There might be linkers that let you do some kind of remapping of names to help avoid collisions. A side-effect of that might be they allow you to say thisFunction -> this, and not have a problem with the right hand side of the mapping being a keyword.
In any case...the better answer if you can change it is...change it!
If extern "C" allowed you to use C++ keywords as symbols, the compiler would have to resolve them somehow outside of the extern "C" sections. For example:
extern "C" {
int * this; //global variable
typedef int class;
}
int MyClass::MyFunction() { return *this; } //what does this mean?
//MyClass could have a cast operator
class MyOtherClass; //forward declaration or a typedef'ed int?
Could you be more explicit about "using the this name for some variables in one of its header files"?
Is it really a variable or is it a parameter in a function prototype?
If it is the latter, you don't have a real problem because C (and C++) prototypes identify parameters by position (and type) and the names are optional. You could have a different version of the prototype, eg:
#ifdef __cplusplus
extern "C" {
void aFunc(int);
}
#else
void aFunc(int this);
#endif
Remember there is nothing magic about header files - they just provide code which is lexically included in at the point of #include - as if you copied and pasted them in.
So you can have your own copy of a library header which does tricks like the above, just becoming a maintenance issue to ensure you track what happens in the original header. If this was likely to become an issue, add a script as a build step which runs a diff against the original and ensures the only point of difference is your workaround code.

Using a mixed C/C++ header to use C++ object in C

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

Regarding C++ class access/manipulation in C

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:
foo.h, header that'll list all prototypes that C/C++ will see (classes invisible to C of course)
foo.cpp containing the Foo class, and a set of C-compatible callback functions to invoke the class and methods.
fooWrap.c a set of C-specific wrappers that reference the callback functions in foo.cpp.
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
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.