简体   繁体   English

C++ 类或结构与 C 结构的兼容性

[英]C++ Class or Struct compatiblity with C struct

Is it possible to write a C++ class or struct that is fully compatible with C struct.是否可以编写一个与 C 结构完全兼容的 C++ 类或结构。 From compatibility I mean size of the object and memory locations of the variables.从兼容性我的意思是对象的大小和变量的内存位置。 I know that its evil to use *(point*)&pnt or even (float*)&pnt (on a different case where variables are floats) but consider that its really required for the performance sake.我知道使用*(point*)&pnt甚至(float*)&pnt (在变量是浮点数的不同情况下(float*)&pnt是邪恶的,但考虑到它确实是为了性能而需要的。 Its not logical to use regular type casting operator million times per second.每秒使用一百万次常规类型转换运算符是不合逻辑的。

Take this example拿这个例子

Class Point {
    long x,y;
    Point(long x, long y) {
        this->x=x;
        this->y=y;
    }

    float Distance(Point &point) {
        return ....;
    }
};

C version is a POD struct C 版本是一个 POD 结构

struct point {
    long x,y;
};

The cleanest was to do this is to inherit from the C struct:最干净的方法是从 C 结构继承:

struct point
{
    long x, y;
};

class Point : public struct point
{
  public:
    Point(long x, long y)
        {    this->x=x; this->y=y; }

    float Distance(Point &point)
        {                return ....;        }
}

The C++ compiler guarantees the C style struct point has the same layout as with the C compiler. C++ 编译器保证 C 风格的结构点具有与 C 编译器相同的布局。 The C++ class Point inherits this layout for its base class portion (and since it adds no data or virtual members, it will have the same layout). C++ 类 Point 为其基类部分继承了此布局(并且由于它不添加数据或虚拟成员,因此将具有相同的布局)。 A pointer to class Point will be converted to a pointer to struct point without a cast, since conversion to a base class pointer is always supported.指向类 Point 的指针将被转换为指向 struct point 的指针,而无需进行强制转换,因为始终支持转换为基类指针。 So, you can use class Point objects and freely pass pointers to them to C functions expecting a pointer to struct point.因此,您可以使用类 Point 对象并自由地将指向它们的指针传递给需要指向 struct point 的指针的 C 函数。

Of course, if there is already a C header file defining struct point, then you can just include this instead of repeating the definition.当然,如果已经有定义结构点的C头文件,那么你可以只包含它而不是重复定义。

Yes.是的。

  • Use the same types in the same order in both languages在两种语言中以相同的顺序使用相同的类型
  • Make sure the class doesn't have anything virtual in it (so you don't get a vtable pointer stuck on the front)确保该类中没有任何虚拟内容(这样您就不会在前面卡住 vtable 指针)
  • Depending on the compilers used you may need to adjust the structure packing (usually with pragmas) to ensure compatibility.根据所使用的编译器,您可能需要调整结构打包(通常使用编译指示)以确保兼容性。

(edit) (编辑)

  • Also, you must take care to check the sizeof() the types with your compilers.此外,您必须注意使用编译器检查 sizeof() 类型。 For example, I've encountered a compiler that stored shorts as 32 bit values (when most will use 16).例如,我遇到过一个编译器将 short 存储为 32 位值(大多数情况下将使用 16 位值)。 A more common case is that an int will usually be 32 bits on a 32-bit architecture and 64 bits on a 64-bit architecture.更常见的情况是 int 在 32 位架构上通常是 32 位,在 64 位架构上通常是 64 位。

POD applies to C++. POD 适用于 C++。 You can have member functions.您可以拥有成员函数。 "A POD type in C++ is an aggregate class that contains only POD types as members, has no user-defined destructor, no user-defined copy assignment operator, and no nonstatic members of pointer-to-member type" “C++ 中的 POD 类型是一个聚合类,它只包含 POD 类型作为成员,没有用户定义的析构函数,没有用户定义的复制赋值运算符,也没有成员指针类型的非静态成员”

You should design your POD data structures so they have natural alignment, and then they can be passed between programs created by different compilers on different architectures.你应该设计你的 POD 数据结构,让它们自然对齐,然后它们可以在不同架构上的不同编译器创建的程序之间传递。 Natural alignment is where the memory offset of any member is divisible by the size of that member.自然对齐是任何成员的内存偏移量可以被该成员的大小整除。 IE: a float is located at an address that is divisible by 4, a double is on an address divisible by 8. If you declare a char followed by a float, most architectures will pad 3 bytes, but some could conceivably pad 1 byte. IE:浮点数位于可被 4 整除的地址上,双精度位于可被 8 整除的地址上。如果声明 char 后跟浮点数,大多数体系结构将填充 3 个字节,但有些体系结构可能会填充 1 个字节。 If you declare a float followed by a char, all compilers (I ought to add a source for this claim, sorry) will not pad at all.如果您声明一个浮点数后跟一个字符,则所有编译器(我应该为此声明添加一个源代码,抱歉)根本不会填充。

C and C++ are different languages but it has always been the C++'s intention that you can have an implementation that supports both languages in a binary compatible fashion. C 和 C++ 是不同的语言,但 C++ 的意图一直是您可以拥有一个以二进制兼容的方式支持这两种语言的实现。 Because they are different languages it is always a compiler implementation detail whether this is actually supported.因为它们是不同的语言,所以它是否真的被支持总是一个编译器实现细节。 Typically vendors who supply both a C and C++ compiler (or a single compiler with two modes) do support full compatibility for passing POD-structs (and pointers to POD-structs ) between C++ code and C code.通常,同时提供 C 和 C++ 编译器(或具有两种模式的单个编译器)的供应商确实支持在 C++ 代码和 C 代码之间传递POD 结构(和指向POD 结构的指针)的完全兼容性。

Often, merely having a user-defined constructor breaks the guarantee although sometimes you can pass a pointer to such an object to a C function expecting a pointer to a struct with and identical data structure and it will work.通常情况下,仅仅具有用户定义的构造断保证虽然有时可以将指针传递给这样的一个目的是C函数期待一个指向struct与和相同的数据结构和它的工作。

In short: check your compiler documentation.简而言之:检查您的编译器文档。

Use the same "struct" in both C and C++.在 C 和 C++ 中使用相同的“结构”。 If you want to add methods in the C++ implementation, you can inherit the struct and the size should be the same as long as you don't add data members or virtual functions.如果要在C++实现中添加方法,可以继承struct,只要不添加数据成员或虚函数,大小应该是一样的。

Be aware that if you have an empty struct or data members that are empty structs, they are different sizes in C and C++.请注意,如果您有一个空结构体或数据成员是空结构体,则它们在 C 和 C++ 中的大小不同。 In C, sizeof(empty-struct) == 0 although in C99, empty-structs are not supposed to be allowed (but may be supported anyway as a "compiler extension").在 C 中, sizeof(empty-struct) == 0 虽然在 C99 中,不应该允许空结构(但无论如何都可以作为“编译器扩展”支持)。 In C++, sizeof(empty-struct) != 0 (typical value is 1).在 C++ 中,sizeof(empty-struct) != 0(典型值为 1)。

In addition to other answers, I would be sure not to put any access specifiers (public:, private: etc) into your C++ class / struct.除了其他答案之外,我肯定不会将任何访问说明符(public:、private: 等)放入您的 C++ 类/结构中。 IIRC the compiler is allowed to reorder blocks of member variables according to visibility, so that private: int a; pubic: int b; IIRC 允许编译器根据可见性对成员变量块重新排序,这样private: int a; pubic: int b; private: int a; pubic: int b; might get a and b swapped round.可能会交换 a 和 b 轮。 See eg this link: http://www.embedded.com/design/218600150?printable=true参见例如此链接: http : //www.embedded.com/design/218600150?printable=true
I admit to being baffled as to why the definition of POD does not include a prohibition to this effect.我承认对为什么 POD 的定义不包括禁止这种效果感到困惑。

As long as your class doesn't exhibit some advanced traits of its kind, like growing something virtual, it should be pretty much the same struct.只要你的类没有表现出一些高级特性,比如增长虚拟的东西,它就应该是几乎相同的结构。

Besides, you can change Class (which is invalid due to capitalization, anyway) to struct without doing any harm.此外,您可以将Class (无论如何由于大写而无效)更改为struct而不会造成任何伤害。 Except for the members will turn public (they are private now).除了成员将公开(他们现在是私人的)。

But now that I think of your talking about type conversion… There's no way you can turn float into long representing the same value or vice versa by casting pointer type.但是现在我想到了您谈论的类型转换……您无法通过转换指针类型将float转换为表示相同值的long或反之亦然。 I hope you only want it these pointers for the sake of moving stuff around.我希望你只是为了移动东西而想要这些指针。

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

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