简体   繁体   English

C++ POD 结构继承? 是否有关于派生成员的内存布局的任何保证

[英]C++ POD struct inheritance? Are there any guarantees about the memory layout of derived members

Let's say, I have a struct RGB and I want to create struct RGBA , which inherits RGB :假设我有一个struct RGB并且我想创建struct RGBA ,它继承了RGB

struct RGB {
    unsigned char r;
    unsigned char g;
    unsigned char b;
};

struct RGBA: RGB {
    unsigned char a;
};

Both will be used for reading uncompressed image data:两者都将用于读取未压缩的图像数据:

RGBA *pixel=static_cast<RGBA *>(image->uncompressed_data);

Question: Is this safe, regarding the memory layout of struct RGBA ?问题:关于struct RGBA的内存布局,这安全吗? Does anyone guarantee, that:有没有人保证:

  • unsigned char a comes after the RGB struct (not before) unsigned char a出现在RGB struct (不是之前)
  • There is no padding between struct RGB and the a parameter from struct RGBA ? struct RGBstruct RGBA的 a 参数之间没有填充?

will #pragma pack help here? #pragma pack在这里有帮助吗? It's all about memory layout during inheritance.这都是关于继承期间的内存布局。

No, the layout is not guaranteed.不,不保证布局。 The only guarantees are for standard-layout classes;唯一的保证是针对标准布局类; and one of the conditions of such a class is that it而这样一个类的条件之一是它

either has no non-static data members in the most derived class and at most one base class with non-static data members, or has no base classes with non-static data members要么在最派生的类中没有非静态数据成员,并且最多有一个具有非静态数据成员的基类,要么没有具有非静态数据成员的基类

In other words, all data members must be in the same class, not in more than one.换句话说,所有数据成员必须在同一个类中,不能超过一个。

There is NO guarantees about the memory layout of derived members and the cast is NOT safe.没有保证有关派生成员的内存布局和演员是不是安全。

As you have inheritance, also there could be padding, this is NOT trivial.因为你有继承,也可能有填充,这不是微不足道的。

§ 9 Classes § 9 类

1 A POD struct109 is a class that is both a trivial class and a standard-layout class , and has no non-static data members of type non-POD struct, non-POD union (or array of such types). 1 POD struct109 是一个既是平凡类又是标准布局类的类,并且没有非 POD 结构、非 POD 联合(或此类类型的数组)类型的非静态数据成员。 Similarly, a POD union is a union that is both a trivial class and a standard layout class, and has no non-类似地,POD 联合是一个既是平凡类又是标准布局类的联合,并且没有非

Also std::is_pod<RGBA> is not a POD另外std::is_pod<RGBA>不是 POD

std::cout << std::boolalpha;
std::cout << std::is_pod<RGBA>::value << '\n';

result is false.结果是假的。 see live demo现场演示

It's easy to check for padding: Print sizeof(RGB) and sizeof(RGBA) .检查填充很容易:打印sizeof(RGB)sizeof(RGBA) If it's not 3 respective 4 then the structures are padded, and you need to remove it.如果它不是 3 和 4,则结构被填充,您需要将其删除。

As for if the member a comes after b , you can use offsetof to check each members offset.至于成员a是否在b之后,则可以使用offsetof来检查每个成员的偏移量。 If the offset for a is one larger than the offset of b then a comes directly after b .如果用于抵消a比所述的偏移较大的一个b然后a后直接来自b

As all previous answers here already stated: it is not guaranteed by the standard.正如这里所有先前的答案已经指出的那样:标准不保证。 But if you still require such an inheritance of PODs (the derived class is actually no POD anymore), you can at least validate that the current compiler behaves as desired, by using static_assert.但是,如果您仍然需要 POD 的这种继承(派生类实际上不再是 POD),您至少可以通过使用 static_assert 验证当前编译器的行为是否符合要求。 If you switch to another compiler that behaves different, then you should at least get compiler errors.如果你切换到另一个行为不同的编译器,那么你至少应该得到编译器错误。 Though, this may be bad practice if your code should be easily portable.但是,如果您的代码应该易于移植,这可能是不好的做法。

I also recommend to use compiler variable attribute __attribute__((packed)) to declare your POD structures and to use <cstdint> .我还建议使用编译器变量属性__attribute__((packed))来声明您的 POD 结构并使用<cstdint> This is valid with eg GCC, but might also be different depending on the compiler you use.这对例如 GCC 有效,但也可能因您使用的编译器而异。

#include <cstdint>

struct __attribute__((packed)) RGB {
    uint8_t r;
    uint8_t g;
    uint8_t b;
};

struct __attribute__((packed)) RGBA : RGB {
    uint8_t a;
};

static_assert( sizeof(RGB) == 3u, "Unexpected size" );
static_assert( sizeof(RGBA) == 4u, "Unexpected size" );

I maybe wrong but seems to me that you can define:我可能错了,但在我看来,您可以定义:

struct RGBA {
    struct RGB base;
    unsigned char g;
};

and (1) RGBA will be POD, and (2) you can cast both ways:和 (1) RGBA 将是 POD,并且 (2) 您可以两种方式进行转换:

RRBA x;
RGB* x_rgb = reinterpret_cast<RGB*>(&x);
RGBA* x_rgba = reinterpret_cast<RGBA*>(x_rgb);

I suspect there will be some padding that may be eliminated by atttribute ((packed)).我怀疑会有一些填充可能会被属性((packed)) 消除。

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

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