有没有办法防止组合类的填充

时间:2016-01-24 21:10:54

标签: c++ padding

假设64位机器:

如果我从A类开始:

struct A
{
    int* a1; //8
    int* a2; //8 
    uint16_t a3; //2
    uint16_t a4; //2

    uint32_t a5; //4
    uint32_t a6; //4
    uint32_t a7; //4
};

现在所有单个成员都有正确的对齐方式,A的大小为32个字节,从a5a1的偏移量为20个字节

现在,如果我尝试按如下方式重构:

struct A_part1
{
    int* a1; //8
    int* a2; //8 
    uint16_t a3; //2
    uint16_t a4; //2
};

struct A_new
{
    A_part1 a1; 
    uint32_t a5; //4
    uint32_t a6; //4
    uint32_t a7; //4
};

现在A_new的大小为40个字节,因为A_part1最多填充24个字节,A_new随后从36个字节填充到40个字节。

据推测,编译器正在尝试确保连续的A_part1对齐。

如果我知道我只会在A_part1使用A,那么我必须在pragma 1上使用a_part包来确保A_new与原始A具有相同的特征?

2 个答案:

答案 0 :(得分:2)

你是对的:标准C ++中没有办法指定struct的填充布局,因此你会遇到像#pragma pack这样的特定于编译器的控制机制。

答案 1 :(得分:1)

  

如果我知道我只会在A中使用A_part1,那么我是唯一的选择   必须在a_part1上使用pragma包来确保A_new   具有与原始A?

相同的特征

没有。 pragma不是指定布局和填充的唯一方法。

在我曾经使用过的嵌入式软件中,我们找到了几种解决pragma问题的方法。

C和C ++都没有提供内存布局语义。

但是,一种易于理解的技术,至少在逐字段的基础上,是明确地编码字节驻留在类或结构中的位置。通过重构和添加小字节移动方法,工作量大大减少。

注意:七个字段很小,因此很“简单”。五十个领域令人厌倦。数百个字段是“让我们编写一些代码来编写代码”。你的容忍度会有所不同。

该技术将字节显式地移动到所需的字节数据中。优点:1)没有填充(除非你想要它)。 2)对编译器选项的变化不敏感。 3)便携式。

小例子(编译,但未测试)(注意:任意字节序选择,我们使用传统的字节序转换)

class A
{
   //   int* a1;     //8  0..7
   //   int* a2;     //8  8..15
   //   uint16_t a3; //2  16..17
   //   uint16_t a4; //2  18..19
   //
   //   uint32_t a5; //4  etc
   //   uint32_t a6; //4
   //   uint32_t a7; //4
   // ...

   // modify field a3
   void a3(uint16_t val) {
      // if needed, correct val for destination endianess ------vvv
      data[Oa3+0] = static_cast<uint8_t>((val >> 0) & 0xff); // LSB
      data[Oa3+1] = static_cast<uint8_t>((val >> 8) & 0xff); // MSB
   }

   // access field a3
   uint16_t  a3() {
      // if needed, correct val for endianess ---------------------vvv
      uint16_t val = static_cast<uint16_t>((data[Oa3+0] << 0) + // LSB
                                           (data[Oa3+8] << 8)); // MSB
      return (val);
   }

   // continue for each field

private:
   enum {
      Oa1 = 0, // Offset a1
      Oa2 = 8,
      Oa3 = 16
      //... etc
   };

   uint8_t data[(8+8+2+2+(3*4))]; 
};