结构体对齐

本文详细介绍了64位编程环境下结构体的对齐原则,包括如何通过编译器选项进行8字节对齐,并提供了具体的示例代码。此外还讨论了不同编译器下的一致性编程技巧。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

我理解的结构体对齐,对于64位的,起址要8字节对齐.这个编译器可以默认帮你完成,你不必在之前加align 8.

结构体内部的对齐可以由两种方式实现:
1.
*** STRUCT  alignment


*** ENDS
其中alignment 可以为1,2,4,8等。
2.
编译时加一个命令: -Zp[n]    这里的n与上面的alignment等效.
比如8字节对齐,可以加上 -Zp8
或用
*** STRUCT  8


*** ENDS

如果同时使用了这两种方式,则*** 结构体仍以alignment为对齐原则,其它的未指定的以-Zp[n]对齐.

所以通常加个-Zp[n] 全局结构体对齐就可以了.

可要注意到,-Zp[n]的n仅仅是一个建议值,它是以min{max{sizeof(结构体元成员的类型)},n}为原则.
比如:
指定了: -Zp8   (即n=8)
则对于:
RECT struct
    left    dd     ?
    top     dd     ?
    right   dd     ?
    bottom  dd     ?
RECT ends
均以4字节对齐,因为 min{max{sizeof(DWORD)},8}=4.

又如:
我们定义了一个64位编程中的MSG结构.
指定了: -Zp8   (即n=8)
MSG struct
  hwnd      dq      ?
  message   dd      ?
  wParam    dq      ?
  lParam    dq      ?
  time      dd      ?
  pt        POINT   <>
MSG ends
则以上MSG结构以8字节对齐,因为 min{max{sizeof(dq)},8}=8.

这个对齐工作是由编译器帮你完成的.而不用你自己实现对齐,形如:
MSG struct
  hwnd       dq      ?
  message    dd      ?
  padding1   dd      ?      ;message成员变量是4字节,所以要填充一个4字节变量
  wParam     dq      ?
  ......
MSG ends
是不必要的.

==============================
总结上面的对齐原则:

对于win32  默认即可,而对于win64至少加上-Zp8对齐,否则对于有>4字节的类型变量时会出错.
或许对于ml64.exe也可以默认,因为它是这么做的.而JWasm则必须加上.

==============================
对于x86或x64 在windows.inc中常量是通用的.
所以我们可以做些小改变,即可实现win32/64的同一inc文件,同一源文件的统一编程.

masm32中的windows.inc 及其它定义未把指针与DWORD数据相区分.

所以我们可以这样来定义:
IFNDEF X64_INC
X64_INC equ <0>
ENDIF

IF X64_INC eq 1
  WPARAM    typedef QWORD
  LPARAM    typedef QWORD
  LPSTR     typedef QWORD

ELSE
  WPARAM    typedef DWORD
  LPARAM    typedef DWORD
  LPSTR     typedef DWORD
ENDIF


POINT STRUCT
  x  DWORD ?
  y  DWORD ?
POINT ENDS

MSG STRUCT
  hwnd      LPSTR      ?
  message   DWORD      ?
  wParam    WPARAM     ?
  lParam    LPARAM     ?
  time      DWORD      ?
  pt        POINT      <>
MSG ENDS

WM_CLOSE               equ 10h
WM_COMMAND             equ 111h
WM_SIZE                equ 5h
WM_PAINT               equ 0Fh
WM_DESTROY             equ 2h

;.....

 

 


 

### 结构体对齐原理 结构体对齐的核心在于优化 **数据存取执行效率** 和减少不必要的 **存储空间浪费** 的平衡[^1]。在嵌入式系统开发中,这种权衡尤为重要,因为内存资源有限而性能需求较高[^2]。 #### 数据对齐规则 1. **成员变量的对齐置**: - 第一个成员始终于偏移量为 `0` 的地址上。 - 后续成员会根据其类型的大小和编译器设定的最大对齐数进行调整,使其地址是对齐数的整数倍。对齐数通常是该成员类型大小与全局默认对齐数之间的最小值[^5]。 2. **整体结构体大小**: - 整个结构体的大小会被扩展为其内部最大对齐数的整数倍。这样可以确保当多个相同结构体组成数组时,每个结构体实例仍然能够保持良好的对齐状态[^4]。 3. **嵌套结构体处理**: - 如果结构体内包含另一个子结构体,则子结构体会以其自身的最大对齐数为准进行填充并扩展至合适的边界长度;最终整个父级结构体也会基于所有成员(包括嵌套部分)的最大对齐数值做进一步扩充。 ### 实现方法 可以通过预处理器指令或者特定函数来改变默认行为: - 使用 `#pragma pack(n)` 设置新的字节打包模式 (n 表示指定的新对齐),从而强制覆盖原有自动计算出来的对齐策略; ```c #include <stdio.h> #pragma pack(1) // 手动设置紧凑排列 typedef struct { char a; int b; short c; } MyStruct; int main() { printf("Size of MyStruct: %lu\n", sizeof(MyStruct)); // 输出应为7而非通常情况下的12或更多 return 0; } ``` - 利用标准库头文件 `<stdalign.h>` 提供的功能实现更灵活精确地控制对象间的相对定关系。 另外需要注意的是,在实际项目里修改这些参数可能带来兼容性和移植性方面的问题,因此需谨慎操作。 ### 示例分析 假设存在如下定义: ```c struct Example { char ch; /* size=1 */ double db; /* size=8 */ }; ``` 如果没有特别指示,默认情况下可能会有以下布局: | 地址 | 类型 | |------|------------| | 0x00 | char(ch) | | 0x01 ~ 0x07 | 填充 | | 0x08 ~ 0x10 | double(db)| 这里为了使双精度浮点数能高效加载到寄存器内工作,它前面预留了足够的空白区域作为补偿措施。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值