我试图在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.我的包装代码有问题吗?还是我误解了整个概念?
答案 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)
与32位系统相比,LP64 64位系统的对齐唯一显着差异是:
某些数据类型取决于实现。
#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);
希望它能让你理解,即使我宣布你的结构错了。