I'm building a C++ library which uses many functions and struct
's defined in a C library. To avoid porting any code to C++, I add the typical conditional preprocessing to the C header files. For example,
//my_struct.h of the C library
#include <complex.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef struct {
double d1,d2,d3;
#ifdef __cplusplus
std::complex<double> z1,z2,z3;
std::complex<double> *pz;
#else
double complex z1,z2,z3;
double complex *pz;
#endif
int i,j,k;
} my_struct;
//Memory allocating + initialization function
my_struct *
alloc_my_struct(double);
#ifdef __cplusplus
}
#endif
The implementation of alloc_my_struct()
is compiled in C. It simply allocates memory via malloc()
and initializes members of my_struct
.
Now when I do the following in my C++ code,
#include "my_struct.h"
...
my_struct *const ms = alloc_my_struct(2.);
I notice that *ms
always have the expected memory layout, i.e., any access such as ms->z1
evaluates to the expected value. I find this really cool considering that (correct me if I'm wrong) the memory layout of my_struct
during allocation is decided by the C compiler (in my case gcc -std=c11
), while during access by the C++ compiler (in my case g++ -std=c++11
).
My question is : Is this compatibility standardized? If not, is there any way around it?
NOTE : I don't have enough knowledge to argue against alignment, padding, and other implementation-defined specifics. But it is noteworthy that the GNU scientific library, which is C-compiled, is implementing the same approach (although their struct
s do not involve C99 complex numbers) for use in C++. On the other hand, I've done sufficient research to conclude that C++11 guarantees layout compatibility between C99 double complex
and std::complex<double>
.
A C program memory layout in C mainly comprises six components these are heap, stack, code segment, command-line arguments, uninitialized and initialized data segments. Each of these segments has its own read, write permissions.
Struct members are stored in the order they are declared. (This is required by the C99 standard, as mentioned here earlier.) If necessary, padding is added between struct members, to ensure that the latter one uses the correct alignment. Each primitive type T requires an alignment of sizeof(T) bytes.
Heap is the segment where dynamic memory allocation usually takes place. When some more memory need to be allocated using malloc and calloc function, heap grows upward. The Heap area is shared by all shared libraries and dynamically loaded modules in a process.
A stack is a linear data structure, collection of items of the same type. Stack follows the Last In First Out (LIFO) fashion wherein the last element entered is the first one to be popped out. In stacks, the insertion and deletion of elements happen only at one endpoint of it.
C and C++ do share memory layout rules. In both languages structs are placed in memory in the same way. And even if C++ did want to do things a little differently, placing the struct inside extern "C" {}
guarantees C layout.
But what your code is doing relies on C++ std::complex and C99 complex to be the same.
So see:
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