C 编译器打包问题

打包级别以相同的方式影响 MIDL 和 Microsoft C/C++ 编译器类型的内存布局。 在 Microsoft 生成环境(例如 VC++ 或平台软件开发工具包 (SDK) 定义的生成环境)中,MIDL 和 C/C++ 编译器的默认打包级别相同:32 位和 64 位 Windows 生成环境的默认打包级别为 8。

自然对齐

对于内存中的类型,默认对齐方式与其自然对齐方式相同。

  • 基类型(如 short、float 和 __int64),如果指针的表示形式从其大小相等的地址开始,则指针自然对齐。 当前支持的所有基类型的大小为 1、2、4 或 8。 指针在 32 位环境中的大小为 4,在 64 位环境中为 8。
  • 如果复合类型的每个组件相对于类型开头自然对齐,并且组件之间没有不必要的间隙 (填充) ,则复合类型自然对齐。 复合组件(如字段或元素)将递归为指针或基类型组件。

帮助记住此行为的一个简单规则是,类型的自然对齐方式等于其组件的最大对齐方式。

C 或 C++ 和 IDL 等语言中的某个类型的对齐方式与内存大小之间存在连接,由运算符 sizeof () 表示。 大小是对齐方式 (跨越类型) 的最小倍数的倍数。 这后跟内存中的数组表示形式。

自然对齐非常重要,因为访问未对齐的数据可能会导致某些系统上出现异常。 数据在未对齐时可以标记为安全操作,但这通常涉及速度损失,在某些平台上可能相当严重。

注意

在内存中,当放置在 n 的倍数的地址时,保证正确对齐 n 的类型的对象。

 

打包与对齐

指定大于类型自然对齐方式的打包级别不会更改类型对齐方式。 指定小于自然对齐方式的打包级别会将类型对齐方式降低到打包级别。 因此,打包类型可能会放置在内存中,这些地址是打包级别的倍数, (减少的对齐) ,而不会造成错位。 这会影响简单类型和组件类型。 对于复合类型,类型的内部布局可能会受到影响,因为组件的对齐方式的减少可能会更改组件正确对齐所需的填充大小,从而减小类型的大小。

帮助记住此行为的一个简单规则是,打包类型的新对齐方式是打包级别的较小及其自然对齐方式。 类型的大小是新对齐方式的倍数。 sizeof () 运算符返回已打包类型的减小大小。

例如,当打包级别为 2 时,一个长变为对齐 2,因此可以放置在任何偶数地址,而不仅仅是位于 4 倍的地址处,自然对齐的情况也是如此。 短和长的结构,包装在 2,不需要短和下长之间的内部间隙,这是自然对齐所必需的:因此,结构不仅现在在 2 对齐,而且其大小也从 8 缩小到 6。

例如,考虑由 1 字节字符、4 字节长整数和 1 字节字符组成的复合类型:

struct mystructtype 
{    
    char c1;  /* requires 1 byte  */
              /* 3 bytes of padding with natural alignment only */
    long l2;  /* requires 4 bytes */
    char c3;  /* requires 1 byte  */
              /* 3 bytes of padding with natural alignment only */
 } mystruct;

此结构在 4 处自然对齐,其自然大小为 12。

对于打包级别 4 或更高版本,结构 mystruct 在 4 处对齐,等于 sizeof(struct mystructtype) 12。 如果位于内存中的地址不是 4 的倍数,则结构将不对齐。

对于包装级别 2,结构在 2 对齐,其大小为 8。 如果位于内存中不是 2 的倍数的地址,则包含级别 2 的结构将错位。

对于打包级别 1,结构在 1 对齐,其大小为 6。 使用级别 1 打包的结构可以放置在任何位置,而不会导致错位错误。

/Zp

/包