我很难理解为什么下面的代码(带有标准布局的UDT)在visual C ++ 2012中给出了C-linkage警告:
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
}
该函数的定义在C ++文件中:
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);
}
答案 0 :(得分:7)
原因是当您使用C ++编译器编译该代码时,预处理的代码如下所示:
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);
}
所以编译器看到的函数'vec3_add'被声明为具有C链接,但是使用类型'vec3',它具有C编译器无法理解的构造函数。 C ++编译器不知道C编译器不会看到构造函数,因此会发出警告。请记住,预处理在编译之前发生,因此在报告警告时编译器看不到#ifdef __cplusplus
行。
此类问题的常见模式是:
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
通过这种方式,C ++代码可以在调用'vec3_add'时使用'CVec3'类型而不是'vec3'类型。 C代码只能看到'vec3'POD类型。
答案 1 :(得分:0)
错误信息很清楚;当您使用extern "C"
时,您只能使用与C ABI兼容的代码。非POD结构(例如带有用户定义构造函数的struct)与C ABI不兼容。
您应该从结构定义中删除它:
#ifdef __cplusplus
vec3(float x, float y, float z) : x(x), y(y), z(z) {}
#endif
无论如何,它可能会导致未定义的行为,因为添加它可能会导致结构布局发生变化。如果您希望能够在C ++代码中整齐地构造vec3
,那么请编写一个函数来执行此操作,例如。
vec3 make_vec3(float x, float y, float z) { vec3 v; v.x=x; v.y=y; v.z.z; return v; }
此外,您应该将整个标头包装在extern "C"
中(除了包含标准标头的标头),而不仅仅是它的一部分。
答案 2 :(得分:-1)
我相信你需要在cxx文件中再次声明vec3_add是一个C连接函数:
extern "C" 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);
}