C++代码链接中的错误:警告 C4190:类型指定了 C 链接,但返回与 C 不兼容的 UDT

Error in C++ code linkage: warning C4190: type has C-linkage specified, but returns UDT which is incompatible with C

本文关键字:链接 返回 UDT 不兼容 类型 错误 代码 警告 C4190 C++      更新时间:2023-10-16

我很难理解为什么以下代码(具有标准布局的UDT)在Visual C++ 2012中给出C链接警告:

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

原因是当您使用 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);
}

因此,编译器看到的是声明为具有 C 链接的函数 'vec3_add',但使用类型 '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 类型。

错误消息非常清楚;当您使用extern "C"时,您只能使用与 C ABI 兼容的代码。非 POD 结构(例如,具有用户定义构造函数的结构)与 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"中(其中包含的标准标头除外),而不仅仅是其中的零碎部分。

我相信您需要在 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);
}