I am having a hard time understanding why the following code (UDT with standard layout) gives a C-linkage warning in visual C++ 2012:
warning C4190: 'vec3_add' has C-linkage specified, but returns UDT 'vec3' which is incompatible with C
typedef struct vec3 {
float x;
float y;
float z;
#ifdef __cplusplus
vec3(float x, float y, float z) : x(x), y(y), z(z) {}
#endif
} vec3;
#ifdef __cplusplus
extern "C" {
#endif
vec3 vec3_add(vec3 a, vec3 b);
#ifdef __cplusplus
}
The definition of the function is in a C++ file:
vec3
vec3_add(vec3 a, vec3 b) {
static_assert(std::is_standard_layout<vec3>::value == true, "incompatible vec3 type");
return vec3(a.x + b.x, a.y + b.y, a.z + b.z);
}
The reason is when you compile that code with a C++ compiler, the preprocessed code looks like this:
typedef struct vec3 {
float x;
float y;
float z;
vec3(float x, float y, float z) : x(x), y(y), z(z) {}
} vec3;
extern "C" {
vec3 vec3_add(vec3 a, vec3 b);
}
So what the compiler sees is the function 'vec3_add' declared as having C linkage, but using the type 'vec3' which has as a constructor which a C compiler won't understand. The C++ compiler doesn't know that a C compiler won't see the constructor so emits the warning. Remember, preprocessing happens before compilation, so the #ifdef __cplusplus
lines are not visible to the compiler at the time when the warning is reported.
A common pattern for this sort of issue is:
extern "C" {
typedef struct vec3 {
float x;
float y;
float z;
} vec3;
vec3 vec3_add(vec3 a, vec3 b);
}
#ifdef __cplusplus
struct CVec3 :vec3 {
CVec3(float X, float Y, float Z) { x = X; y = Y; z = Z; }
};
#endif
In this way, C++ code can use the 'CVec3' type instead of the 'vec3' type in calls to 'vec3_add'. C code will only see the 'vec3' POD type.
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