Windows 10中的类型转换问题(WinAPI中的DWORD和ULONG_PTR)

时间:2018-12-03 07:04:20

标签: c++ windows winapi

在Windows 7中,VS2012编译器

PostQueuedCompletionStatus(hCompletionPort, 0, (DWORD) pContext, &pOverlap->m_ol);

上面的API调用工作正常。

但是在Windows 10和VS2017编译器上,无法访问pContext结构中的成员变量。

当我们从DWORD更改为ULONG_PTR时,它在Windows 10中可以正常工作

PostQueuedCompletionStatus(hCompletionPort, 0, (ULONG_PTR) pContext, &pOverlap->m_ol);

这种行为的原因是什么?

1 个答案:

答案 0 :(得分:8)

很可能新版本不仅在Windows版本中有所不同,而且您还在编译为64位,而以前是32位。

更新 :OP澄清了两个版本都是64位的,但这很容易解释。见下文。

即使在Windows 7/32位上,强制转换为DWORD在概念上也是错误的。实际上,API定义需要ULONG_PTR,它是一个无符号整数类型,其大小足以容纳一个指针而不会丢失数据。因此,编译为32位时为32位类型,编译为64位时为64位。

相反,您将指针投射到DWORD上; DWORD始终是32位无符号类型,因此,在构建32位Windows时,一切都进行得很顺利(指针只需要不超过32位即可完整地到达另一端),但是在64位Windows上,您将失去顶部指针的32位。

现在,此甚至可以在64位Windows 7上运行;为什么?

如注释中所述,此指针来自堆,默认情况下,在Windows 7上,堆从64位地址空间的“低”部分开始提供内存。因此,除非您消耗大量内存,否则您将始终获得前32位为零的地址,因此即使将前32位砍掉也可以继续使用。

This changed since Windows 8,因为ASLR(在构建64位可执行文件时默认由链接器启用)使堆在虚拟地址空间中的位置随机化,这意味着您将获得具有非零上位的指针32位,将被强制转换为DWORD

长话短说:修复您的演员表 1 ,一切都会正常。另外,将来始终要警惕从指针到不以_ptr_PTR结尾的整数类型的强制转换-您很可能会犯错。


注释

  1. 严格来说,IIRC标准要求“强制通过” void *才能使这些强制转换正常工作,即,仅针对uintptr_t保证通过void *的往返(也许{{1 }}?我必须检查标准),如果char *还不是(ULONG_PTR)(LPVOID)pContext,则应该为pContext。但是,这是Win32,我敢肯定,即使没有额外的转换,它也能保证正常工作。