简体   繁体   English

将 C 识别的指针定义为内部 C++ class

[英]typedefing a pointer recognized by C to an inner C++ class

I have a class that I want to share between C and C++, where C is only able to get it as a pointer.我有一个 class 我想在 C 和 C++ 之间共享,其中 Z0D61F8370CAD14D61F8370CAD14D412F80B84 只能作为指针获取。 However because it is an inner class it cannot be forward-declared.然而,因为它是一个内部 class 它不能被前向声明。 Instead this is what our current code does in a common header file:相反,这是我们当前代码在一个常见的 header 文件中所做的:

#ifdef __cplusplus
class Container {
public:
    class Object {
        public:
        int x;
    };
};

typedef Container::Object * PObject;
#else

typedef void* PObject;

#endif

This looks like it violates the one definition rule (ODR), because C and C++ see different definition using the #ifdef .这看起来违反了单一定义规则 (ODR),因为 C 和 C++ 使用#ifdef看到不同的定义。 But because this is a pointer, I'm not sure if this creates a real problem or not.但是因为这是一个指针,我不确定这是否会造成真正的问题。 C only uses the pointer in order to pass it to C++ functions, it doesn't directly do anything with it. C 仅使用指针将其传递给 C++ 函数,它不直接对其进行任何操作。 For instance this code in the common header file:例如,常见 header 文件中的代码:

#ifdef __cplusplus
extern "C" {
#endif
int object_GetX(PObject pObject);

#ifdef __cplusplus
}
#endif /* __cplusplus */

This as how we implemented it in the C++ file:这就是我们在 C++ 文件中实现它的方式:

int object_GetX(PObject pObject) {
    return pObject->x;
}

My questions are:我的问题是:

  1. Would violating the ODR like this cause any real problems?像这样违反 ODR 会导致任何实际问题吗?
  2. If so, is there another convenient way to share the class to C?如果是这样,是否有另一种方便的方法可以将 class 共享到 C?

First of all, type-aliasing pointers is usually a recipe for trouble.首先,类型别名指针通常会带来麻烦。
Don't do it.不要这样做。

Second, the "inner" class is an overused concept, so my first reflex would be to consider whether it's really necessary.其次,“内部” class 是一个过度使用的概念,所以我的第一反应是考虑它是否真的有必要。

If it is necessary, you can define an opaque empty type and derive from it for some type safety:如果有必要,您可以定义一个不透明的空类型并从中派生一些类型安全性:

In a shared header:在共享 header 中:

struct OpaqueObject;

#ifdef __cplusplus
extern "C" {
#endif

int object_GetX(OpaqueObject* pObject);

#ifdef __cplusplus
}
#endif /* __cplusplus */

In a C++ header:在 C++ header 中:


struct OpaqueObject {};

class Container {
public:
    class Object : public OpaqueObject {
        public:
        int x;
    };
};


Implementation:执行:

int object_GetX(OpaqueObject* pObject) {
    return static_cast<Container::Object*>(pObject)->x;
}

Would violating the ODR like this cause any real problems?像这样违反 ODR 会导致任何实际问题吗?

"Real problems"? “真正的问题”? Maybe.也许。 Maybe not.也许不吧。

There is no "mix C/C++ ODR rule".没有“混合 C/C++ ODR 规则”。 Rules are "contained" within one programming language, specification are written for one programming language.规则被“包含”在一种编程语言中,规范是为一种编程语言编写的。 C++ has its own rules and C++ ihas ODR rule. C++有自己的规则,C++有ODR规则。 C has its own rules, and C does not know anything about ODR. C有自己的规则,C对ODR一无所知。 Other programming languages have their own rules.其他编程语言有自己的规则。

You are not violating ODR in C++ - C++ sees a single one definition of Container everywhere.您没有违反 C++ 中的 ODR - C++ 到处都看到一个单一的 Container 定义。

The stuff in extern "C" uses C calling convention, that I could assume that it also adheres to the C language. extern "C"中的内容使用 C 调用约定,我可以假设它也遵守 C 语言。 In this case, you are just violating rule https://port70.net/~nsz/c/c11/n1570.html#6.5.2.2p9 .在这种情况下,您只是违反了规则https://port70.net/~nsz/c/c11/n1570.html#6.5.2.2p9 Let's say this is like ODR in C for functions.假设这类似于 C 中的 ODR 功能。

If not, you are violating something between languages, that would be ABI.如果不是,那么您就违反了语言之间的某些东西,那就是 ABI。 You pass the value of a void * pointer from C side and your function reads a value of Container::Object * pointer from C++ side. You pass the value of a void * pointer from C side and your function reads a value of Container::Object * pointer from C++ side. That could be allowed by the specific ABI your compilers are using, it could be unspecified.这可能是您的编译器正在使用的特定 ABI 允许的,它可能未指定。 The safe approach would be to assume that it is not allowed.安全的方法是假设它是不允许的。

is there another convenient way to share the class to C?是否有另一种方便的方法可以将 class 共享到 C?

C language also offers static type checking just like C++, but by using void * you are basically turning it off. C 语言也提供 static 类型检查,就像 C++ 一样,但是通过使用void *你基本上是在关闭它。 Do not mix C++ with C.不要将 C++ 与 C 混合使用。 Just have a different unique name for C side, you will be way less confused.只需为 C 端取一个不同的唯一名称,您就不会那么困惑了。

Also, pObject vs PObject ?另外, pObjectPObject Your shift must be fast!你的班次一定要快!

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM