将代码移植到32位和64位Microsoft Windows的编译是很简单的。 您只需遵循一些关于转换指针的简单规则,并在代码中使用新的数据类型。 指针操作的规则如下。
- 不要将指针强制转换为int,long,ULONG或DWORD。
如果必须转换指针以测试某些位,设置或清除位或以其他方式操作其内容,请使用UINT_PTR或INT_PTR类型。 这些类型是整数类型,可扩展为32位和64位Windows的指针大小(例如,对于32位Windows为ULONG,对于64位Windows为_int64)。 例如,假设您正在移植以下代码:
ImageBase=(PVOID)((ULONG)ImageBase|1);
作为移植过程的一部分,您可以按如下方式更改代码:
ImageBase=(PVOID)((ULONG_PTR)ImageBase|1);
在适当的地方使用UINT_PTR和INT_PTR(如果你不确定它们是否是必需的,那么使用它们就没有害处)。不要将指针强制转换为ULONG,LONG,INT,UINT或DWORD类型。
请注意,HANDLE被定义为void*,因此将HANDLE值强制转换为ULONG值以测试,设置或清除低2个字节在64位Windows上是错误的。 - 使用PtrToLong或PtrToUlong函数截断指针。
如果必须截断指向32位值的指针,请使用PtrToLong或PtrToUlong函数(在Basetsd.h中定义)。这些函数在调用期间禁用指针截断警告。
小心使用这些功能。使用这些函数之一转换指针变量后,请不要再将其用作指针。这些函数截断地址的高32位,这通常是访问最初由指针引用的内存所需的。使用这些函数而不仔细考虑将导致代码变得不健壮。 - 在可能编译为64位代码的代码中使用POINTER_32值时要小心。当指针分配给64位代码中的本机指针时,编译器将对指针进行符号扩展,而不是对指针进行零扩展。
- 在可能编译为32位代码的代码中使用POINTER_64值时要小心。编译器将使用32位代码对指针进行符号扩展,而不是对指针进行零扩展。
- 小心使用OUT参数。
例如,假设您有一个定义如下的函数:
void func(OUT PULONG *PointerToUlong);
请勿按如下方式调用此功能。
ULONG ul;
PULONG lp;
func((PULONG*)&ul);
lp=(PULONG)ul;
而是使用以下调用。
PULONG lp;
func(&lp);
类型转换&ul
到PULONG*可防止编译器错误,但该函数会将一个64位指针值写入&ul
的内存中。此代码适用于32位Windows,但会导致64位Windows上的数据损坏,并且它将是微妙的,难以查找的损坏。本质上说:不要用C代码耍花招 - 直截了当,简单就好了。
6.小心多态接口。
不要创建接受多态数据的DWORD参数的函数。如果数据可以是指针或整数值,请使用UINT_PTR或PVOID类型。
例如,不要创建一个接受键入为DWORD值的异常参数数组的函数。该数组应该是DWORD_PTR值的数组。因此,数组元素可以保存地址或32位整数值。 (一般规则是如果原始类型是DWORD并且它需要是指针宽度,则将其转换为DWORD_PTR值。这就是为什么存在相应的指针精度类型。)如果您的代码使用DWORD,ULONG或其他32位类型采用多态方式(也就是说,您确实希望参数或结构成员保存地址),使用UINT_PTR代替当前类型。
7.使用新的窗口类函数。
如果您有包含指针的窗口或类私有数据,则您的代码将需要使用以下新函数:
这些功能可以在32位和64位Windows上使用,但在64位Windows上是必需的。现在使用这些函数准备过渡。
此外,您必须使用64位Windows上的新功能访问类私有数据中的指针或句柄。为了帮助您找到这些情况,在64位编译期间,Winuser.h中未定义以下索引:
- GWL_WNDPROC
- GWL_HINSTANCE
- GWL_HWDPARENT
- GWL_USERDATA
相反,Winuser.h定义了以下新索引:
- GWLP_WNDPROC
- GWLP_HINSTANCE
- GWLP_HWNDPARENT
- GWLP_USERDATA
- GWLP_ID
例如,以下代码无法编译:
SetWindowLong(hWnd,GWL_WNDPROC,(LONG)MyWndProc);
它应该改为如下:
SetWindowLongPtr(hWnd,GWLP_WNDPROC,(LONG_PTR)MyWndProc);
设置WNDCLASS结构的cbWndExtra成员时,请确保为指针保留足够的空间。 例如,如果您当前为指针值保留sizeof(DWORD)字节,请保留sizeof(DWORD_PTR)字节。
8.使用FIELD_OFFSET访问所有窗口和类数据。
通常使用硬编码偏移来访问窗口数据。 此技术无法移植到64位Windows。 要使代码可移植,请使用FIELD_OFFSET宏访问窗口和类数据。 不要假设第二个指针的偏移量为4。
9.LPARAM,WPARAM和LRESULT类型随平台更改大小。
在编译64位代码时,这些类型会扩展为64位,因为它们通常包含指针或整数类型。 请勿将这些值与DWORD,ULONG,UINT,INT,int或long值混合使用。 检查您如何使用这些类型,并确保不会无意中截断值。