2506,字节对齐
原文
客户发现,如果他们传递的统一串
(在窗口
中是指,按使用双字节数据
类型的wchar_t
作为代码单元
的UTF-16LE
编码的串),不在偶数地址
上,则某些(但不是全部)函数无法接受这些串
.
为什么没有记录?
这是编程的基本规则
之一:除非显式允许
,否则指针必须正确
对齐.
在C/C++
语言中,显式按不返回任何有用的值
指定构成未对齐的指针
.
在C
中:
如果生成的指针
没有正确对齐引用的类型
,则行为未定义
.
在C++
中:
expr.static.cast
中,如果原始指针
值表示内存中字节的A
地址,且A不满足T的对齐要求
,则未指定生成的指针值
.
因此,简单创建一个未对齐的指针
已将你带到允许的(在C中)或至少有意义的(在C++
中)操作之外,因此使用未对齐的指针
会导致无意义
,不应感到惊讶.
至于为什么某些函数
比其他函数
更不安,这完全根据这些函数
如何使用指针
及谁检测到未对齐的指针
.
如果你正在使用对齐敏感
的处理器
,当代码试从该指针读取数据
时,就会失败.如果在用户模式
下访问,会得到访问冲突异常
,且进程可能会崩溃
.
如果在内核模式
下访问,则内核模式
验证参数器可能会返回无效的参数
错误.内核模式
必须保护自身免受用户模式
的影响.
如果你使用的处理器
可容忍,未对齐的数据
访问,则临时摆脱它,直到代码对需要对齐的数据
执行某些作.如,原子操作
一般需要对齐数据
,即使在一般允许错位的处理器
上也是.
尽管x86-64
一般对对齐持宽容态度
,但仍有一些地方对对齐敏感
.如,一些涉及SIMD
的寄存器
的指令需要对齐.
SIMD
的寄存器
一般用来复制内存块
,因为wchar_t
有2字节
对齐,因此用来复制块的猜
语句在16
个中只有8个合法起点
,因为所有奇数地址
都是无效的.
如果你传递一个奇数地址
,则很可能会通过猜
语句并执行垃圾复制
.
微软C++
的编译器
有一个特殊的非标准的__unaligned
关键字,用来声明,可能未对齐指针
,这告诉编译器
任何访问该指针背后
的数据
,都必须使用对齐宽容
的指令.
对某些处理器
,非常贵.
在显式允许未对齐指针
的位置上,限制使用未对齐指针
.可通过查找窗口SDK
的UNALIGNED
宏来查找这些位置
.如:
LWSTDAPI_(int)SHFormatDateTimeA(_In_ const FILETIME UNALIGNED * pft,//.._Inout_opt_ DWORD * pdwFlags,_Out_writes_(cchBuf) LPSTR pszBuf,UINT cchBuf);