打包的struct没有预期的大小

时间:2015-09-02 06:28:48

标签: c++ struct

我试图在C ++中打包一个结构,如下所示:

#pragma pack(push, 1)

typedef struct // struct should be 4 byte in size
  {
    BYTE mValue1;
    BYTE mValue2;
    UINT mValue3 : 5;
    UINT mValue4 : 11;
  } MyPackedStruct;

  // Size should be 4, but it actually is 6
const int kMyPackedStructSize = sizeof(MyPackedStruct);

#pragma pack( pop )

我原本期望kMyPackedStructSize为4个字节,但事实并非如此。编译器告诉我它是6.我的包装代码有问题吗?还是我误解了整个概念?

3 个答案:

答案 0 :(得分:2)

今天大多数平台的int(UINT)为4个字节。这将给出6个字节。

答案 1 :(得分:2)

如果您确实想知道发生了什么,您需要查看下面的级别。例如,以下程序会告诉您如何总体结构很大,以及BYTE字段:

#include <stdio.h>

typedef unsigned char BYTE;
typedef unsigned int UINT;

#pragma pack(push, 1)
typedef struct {
    BYTE mValue1;    BYTE mValue2;
    UINT mValue3:5;  UINT mValue4:11;
} MyPackedStruct;
MyPackedStruct x;
#pragma pack( pop )

int main (void) {
    printf ("%zd\n", sizeof(x));
    printf ("%zd\n", sizeof(x.mValue1));
    return 0;
}

不幸的是,你不能以同样的方式获得位字段的大小,为此,你需要进入汇编级别,例如:

#include <stdio.h>

typedef unsigned char BYTE;
typedef unsigned int UINT;

#pragma pack(push, 1)
typedef struct {
    BYTE mValue1;    BYTE mValue2;
    UINT mValue3:5;  UINT mValue4:11;
} MyPackedStruct;
MyPackedStruct x;
#pragma pack( pop )

int main (void) {
    x.mValue3 = 21;    //       10101
    x.mValue4 = 1198;  // 10010101110
    return 0;
}

基本思想是将其转换为汇编,然后检查代码以查看它如何设置值。这会让你知道他们是如何构建的。例如,在我的gcc环境下,它会将各个位加载到eax中,但只使用al中的低8位,然后出现:

movzbl  _x+2, %eax
andl    $-32, %eax    ;; -32 = 111_00000, clears lower 5 bits
orl     $21, %eax     ;; then store 21 (10101) into those bits
movb    %al, _x+2     ;; hence val3 uses lower 5 bits of third byte

movzbl  _x+2, %eax
andl    $31, %eax     ;; 31 = 000_11111, clear all upper bits
orl     $-64, %eax    ;; -64 = 110_00000, 110 is the (lower of 1198)
movb    %al, _x+2

movzbl  _x+3, %eax
andl    $0, %eax      ;; clear all bits
orl     $-107, %eax   ;; stores 10010101 into fourth byte (upper of 1198)
movb    %al, _x+3     ;; so val4 uses all fourth byte and 3 bits of third

因此,在这种特殊情况下,完整大小为32位,因此分配:

--- increasing memory addresses -->
11111111 22222222 55533333 44444444
\______/ \______/ \_/\___/ \______/
 value1   value2   | value3   | value4
                   \__________/  (4s then 5s)

现在你可能最终会得到一个完全不同的布局,毕竟这种事情完全取决于实现。我只是向您展示了几种解决问题的方法。

答案 2 :(得分:1)

  • 字符(一个字节)将以1字节对齐。
  • 短(两个字节)将是2字节对齐的。
  • int(四个字节)将是4字节对齐的。
  • 长(四个字节)将是4字节对齐。
  • 浮点数(四个字节)将是4字节对齐的。
  • 双重( 8字节)将在Windows上进行8字节对齐,在Linux上进行4字节对齐( 8字节,带-malign-double编译时选项 )。
  • 长的( 8个字节)将是8字节对齐的。
  • 一个long double(C ++ Builder和DMC的十个字节,使用Visual C ++的八个字节,十二个GCC的字节)将与C ++ Builder进行8字节对齐,2字节与DMC对齐,8字节与Visual C ++对齐,4字节与GCC对齐。
  • 任何指针(四个字节)将是4字节对齐的。 (例如:char *,int *)

与32位系统相比,LP64 64位系统的对齐唯一显着差异是:

  • 长(八个字节)将是8字节对齐的。
  • 双(八字节)将是8字节对齐的。
  • 一个long double( 8个字节,使用Visual C ++,16个字节使用GCC )将与Visual C ++进行8字节对齐, 与GCC对齐16字节。
  • 任何指针(八个字节)将是8字节对齐的。

某些数据类型取决于实现。

#pragma pack(push, 1)

    typedef struct // struct should be 4 byte in size
      {
        unsigned char mValue1;
        unsigned char mValue2;
        unsigned char mValue3 : 5;
        unsigned char mValue4 : 11;
      } MyPackedStruct;

      // Size should be 4 now, but depends if unsigned char will work for you
    const int kMyPackedStructSize = sizeof(MyPackedStruct);

希望它能让你理解,即使我宣布你的结构错了。