C ++代码链接出错:警告C4190:type指定了C-linkage,但返回与C不兼容的UDT

时间:2014-04-07 00:21:16

标签: c++ c dll

我很难理解为什么下面的代码(带有标准布局的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);
}

3 个答案:

答案 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);
}