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

问题描述 投票:0回答:4

我很难理解为什么以下代码(具有标准布局的 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++ c dll
4个回答
18
投票

原因是当您使用 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
投票

错误信息非常清楚;当您使用

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"
中(其中包含的标准标头除外),而不仅仅是其中的一部分。


0
投票

刚刚遇到类似的问题。我通过将结构包装到联合中来解决这个问题,就 ABI 而言,联合将构造函数从其中剥离出来。

#if !defined(__cplusplus)
    #define VEC3_RETURN_VALUE vec3
#else
    union VEC3_RETURN_VALUE {
        vec3 vec;
        operator vec3() const { return vec; }
    };
#endif

vec3_add(vec3 a, vec3 b);

-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);
}
© www.soinside.com 2019 - 2024. All rights reserved.