I am attempting to write use the this C library without modification in a C++ application. It uses C11 atomics.
Consider the following program, which we can put in a file called main.cc
.
#include "mpscq.h"
int main(){}
If I compile this with the g++ -std=c++11 -c main.cc
, I get a whole collection of errors that look like the following.
usr/lib/gcc/x86_64-linux-gnu/4.9/include/stdatomic.h:68:9: error: ‘_Atomic’ does not name a type
typedef _Atomic __UINT_FAST32_TYPE__ atomic_uint_fast32_t;
^
/usr/lib/gcc/x86_64-linux-gnu/4.9/include/stdatomic.h:69:9: error: ‘_Atomic’ does not name a type
typedef _Atomic __INT_FAST64_TYPE__ atomic_int_fast64_t;
Is it possible to fix these errors without any modification to the library code?
That is, I am willing to use whatever magic incantations are needed in my c++ code or my compiler flags, but I'd rather not change the library code.
I have seen this answer but it requires modification of the header file.
Is it possible to fix these errors without any modification to the library code?
C++ does not have an _Atomic
type qualifier, but the structure declared in the library header has members, including the first, with _Atomic
-qualified type. C++ will not accept this (and wrapping the header inclusion in an extern "C"
block will not help).
C allows objects of _Atomic
-qualified type to have different representations than objects of the non-_Atomic
version of the same type, so in a general sense, this means that C++ cannot directly access any members of any instance of that structure.
If your C implementation happened to use the same representation for corresponding _Atomic
and non-_Atomic
types, then you could probably make your C++ compiler accept the header by #define
ing the symbol _Atomic
to an empty string, but this would be a gateway to more subtle bugs. You could not expect C++ to provide the atomic access semantics that the library expects, so even in this case C++ cannot safely access the structure's members (directly).
If it is sufficient to manipulate instances of the struct
only via the provided functions, then you can do so via opaque pointers. Create a version of the header that provides a forward declaration of the structure, but no definition, and that provides all the function declarations (with C linkage). You C++ code should accept the header and be able to call the functions, both receiving and returning pointers to instances of the structure that it must never try to dereference.
#ifndef __MPSCQ_H
#define __MPSCQ_H
#ifdef __cplusplus
extern "C" {
#endif
struct mpscq;
struct mpscq *mpscq_create(struct mpscq *n, size_t capacity);
// other functions ...
#ifdef __cplusplus
}
#endif
#endif
If you need more than the existing functions provide, then you'll need to write additional helper functions, in C.
You do not need wrapper for using that mpscq in C++ code but you need different header to include it. That would work:
#ifndef MPSCQ_H_FOR_CPP
#define MPSCQ_H_FOR_CPP
extern "C"
{
struct mpscq;
mpscq *mpscq_create(mpscq *n, size_t capacity);
bool mpscq_enqueue(mpscq *q, void *obj);
void *mpscq_dequeue(mpscq *q);
size_t mpscq_count(mpscq *q);
size_t mpscq_capacity(mpscq *q);
void mpscq_destroy(mpscq *q);
}
#endif
That said I would anyway write a wrapper to take care of RAII and such.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With