将 C 识别的指针类型定义为内部 C++ class
typedefing a pointer recognized by C to an inner C++ class
我有一个 class 想在 C 和 C++ 之间共享,其中 C 只能将其作为指针获取。然而,因为它是一个内部 class ,所以它不能被前向声明。相反,这是我们当前的代码在通用头文件中所做的:
#ifdef __cplusplus
class Container {
public:
class Object {
public:
int x;
};
};
typedef Container::Object * PObject;
#else
typedef void* PObject;
#endif
这看起来违反了单一定义规则 (ODR),因为 C 和 C++ 使用 #ifdef
看到了不同的定义。但是因为这是一个指针,我不确定这是否会造成真正的问题。
C 仅使用指针将其传递给 C++ 函数,它不会直接对其执行任何操作。例如公共头文件中的这段代码:
#ifdef __cplusplus
extern "C" {
#endif
int object_GetX(PObject pObject);
#ifdef __cplusplus
}
#endif /* __cplusplus */
这是我们在 C++ 文件中实现它的方式:
int object_GetX(PObject pObject) {
return pObject->x;
}
我的问题是:
- 像这样违反 ODR 会导致任何实际问题吗?
- 如果是这样,是否有另一种方便的方式将 class 共享到 C?
首先,type-aliasing指针通常是一个麻烦的秘诀。
别这样。
其次,“内”class是一个被过度使用的概念,所以我的第一反应是考虑它是否真的有必要。
如果有必要,您可以定义一个不透明的空类型并从中派生以确保类型安全:
在共享中 header:
struct OpaqueObject;
#ifdef __cplusplus
extern "C" {
#endif
int object_GetX(OpaqueObject* pObject);
#ifdef __cplusplus
}
#endif /* __cplusplus */
在 C++ 中 header:
struct OpaqueObject {};
class Container {
public:
class Object : public OpaqueObject {
public:
int x;
};
};
实施:
int object_GetX(OpaqueObject* pObject) {
return static_cast<Container::Object*>(pObject)->x;
}
Would violating the ODR like this cause any real problems?
“真正的问题”?可能是。也许不是。
没有“混合 C/C++ ODR 规则”。规则“包含”在一种编程语言中,规范是为一种编程语言编写的。 C++ 有自己的规则,C++ 有 ODR 规则。 C有自己的规则,C对ODR一无所知。其他编程语言有自己的规则。
您没有违反 C++ 中的 ODR - C++ 在任何地方都看到 Container 的单一定义。
extern "C"
中的内容使用C调用约定,我可以假设它也遵循C语言。在这种情况下,您只是违反了规则 https://port70.net/~nsz/c/c11/n1570.html#6.5.2.2p9 。假设这就像 C 中函数的 ODR。
如果不是,则说明您违反了语言之间的某些内容,那就是 ABI。您从 C 端传递 void *
指针的值,您的函数从 C++ 端读取 Container::Object *
指针的值。您的编译器正在使用的特定 ABI 可能允许这样做,但可能未指定。安全的方法是假设它是不允许的。
is there another convenient way to share the class to C?
C 语言也像 C++ 一样提供静态类型检查,但是通过使用 void *
你基本上将其关闭。不要将 C++ 与 C 混用。只需为 C 端起一个不同的唯一名称,您就不会那么困惑了。
此外,pObject
vs PObject
?你的转变一定要快!
// object.hpp
#ifdef __cplusplus
class Container {
public:
class Object {
public:
int x;
};
};
typedef Container::Object PObject;
extern "C" {
#endif
struct C_PObject {
void *pnt;
};
int object_GetX(struct C_PObject obj);
// ...
// object_c.cpp
PObject *object_from_c(struct C_PObject obj) {
return reinterpret_cast<PObject *>(obj.pnt);
}
extern "C"
int object_GetX(struct C_PObject obj) {
return object_from_c(obj)->x;
}
我有一个 class 想在 C 和 C++ 之间共享,其中 C 只能将其作为指针获取。然而,因为它是一个内部 class ,所以它不能被前向声明。相反,这是我们当前的代码在通用头文件中所做的:
#ifdef __cplusplus
class Container {
public:
class Object {
public:
int x;
};
};
typedef Container::Object * PObject;
#else
typedef void* PObject;
#endif
这看起来违反了单一定义规则 (ODR),因为 C 和 C++ 使用 #ifdef
看到了不同的定义。但是因为这是一个指针,我不确定这是否会造成真正的问题。
C 仅使用指针将其传递给 C++ 函数,它不会直接对其执行任何操作。例如公共头文件中的这段代码:
#ifdef __cplusplus
extern "C" {
#endif
int object_GetX(PObject pObject);
#ifdef __cplusplus
}
#endif /* __cplusplus */
这是我们在 C++ 文件中实现它的方式:
int object_GetX(PObject pObject) {
return pObject->x;
}
我的问题是:
- 像这样违反 ODR 会导致任何实际问题吗?
- 如果是这样,是否有另一种方便的方式将 class 共享到 C?
首先,type-aliasing指针通常是一个麻烦的秘诀。
别这样。
其次,“内”class是一个被过度使用的概念,所以我的第一反应是考虑它是否真的有必要。
如果有必要,您可以定义一个不透明的空类型并从中派生以确保类型安全:
在共享中 header:
struct OpaqueObject;
#ifdef __cplusplus
extern "C" {
#endif
int object_GetX(OpaqueObject* pObject);
#ifdef __cplusplus
}
#endif /* __cplusplus */
在 C++ 中 header:
struct OpaqueObject {};
class Container {
public:
class Object : public OpaqueObject {
public:
int x;
};
};
实施:
int object_GetX(OpaqueObject* pObject) {
return static_cast<Container::Object*>(pObject)->x;
}
Would violating the ODR like this cause any real problems?
“真正的问题”?可能是。也许不是。
没有“混合 C/C++ ODR 规则”。规则“包含”在一种编程语言中,规范是为一种编程语言编写的。 C++ 有自己的规则,C++ 有 ODR 规则。 C有自己的规则,C对ODR一无所知。其他编程语言有自己的规则。
您没有违反 C++ 中的 ODR - C++ 在任何地方都看到 Container 的单一定义。
extern "C"
中的内容使用C调用约定,我可以假设它也遵循C语言。在这种情况下,您只是违反了规则 https://port70.net/~nsz/c/c11/n1570.html#6.5.2.2p9 。假设这就像 C 中函数的 ODR。
如果不是,则说明您违反了语言之间的某些内容,那就是 ABI。您从 C 端传递 void *
指针的值,您的函数从 C++ 端读取 Container::Object *
指针的值。您的编译器正在使用的特定 ABI 可能允许这样做,但可能未指定。安全的方法是假设它是不允许的。
is there another convenient way to share the class to C?
C 语言也像 C++ 一样提供静态类型检查,但是通过使用 void *
你基本上将其关闭。不要将 C++ 与 C 混用。只需为 C 端起一个不同的唯一名称,您就不会那么困惑了。
此外,pObject
vs PObject
?你的转变一定要快!
// object.hpp
#ifdef __cplusplus
class Container {
public:
class Object {
public:
int x;
};
};
typedef Container::Object PObject;
extern "C" {
#endif
struct C_PObject {
void *pnt;
};
int object_GetX(struct C_PObject obj);
// ...
// object_c.cpp
PObject *object_from_c(struct C_PObject obj) {
return reinterpret_cast<PObject *>(obj.pnt);
}
extern "C"
int object_GetX(struct C_PObject obj) {
return object_from_c(obj)->x;
}