【问题标题】:Typecast problem in WIndow 10 (DWORD and ULONG_PTR in WinAPI)WINdow 10 中的类型转换问题(WinAPI 中的 DWORD 和 ULONG_PTR)
【发布时间】:2018-12-03 07:04:20
【问题描述】:

在 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);

这种行为的原因是什么?

【问题讨论】:

  • 根据documentation,该函数将ULONG_PTR 作为第三个参数,所以可能不同之处在于旧编译器让你摆脱它,而新编译器让你知道你是错误的。我猜你可能从编译器那里得到了某种警告。
  • 是的——将整数转换为指针是实现定义的——通常意味着你不能(不应该)依赖这种行为。如果是指针,请使用指针 - 如果是 int,则使用它。在相关说明中,您说“pContext 不可访问” - 在这种情况下,空指针是合适的。
  • @pstrjds 警告?不一定,使用“旧”/32 位编译器,ULONG_PTRDWORD 都可能是相同底层类型的别名...
  • @pstrjds:dw 前缀确实正确的 - 我设法挖掘的包含该功能的最古老的 SDK(Windows NT 4.0 SDK)确实将它作为DWORD;可能后来修复了;实际上,VC++6 中包含的 SDK 已经将其命名为 ULONG_PTR,因此该类型可能在 1996 年至 1998 年之间的某个时间固定。
  • @MatteoItalia - 感谢您的挖掘,此时我只有 VS2017 和最新的 Windows SDK(谢天谢地 - 我曾经从事过一个项目,该项目有一个我们必须在 VC6 和因为有共享代码,我们必须小心我们如何修复与该库共享的部分 - 即共享代码中没有现代 C++ 等)。我在想一定有类似的东西,因为相关函数似乎都使用 lp 前缀表示需要一个指针。

标签: c++ windows winapi


【解决方案1】:

很可能新版本不仅在 Windows 版本上有所不同,而且您也在编译 64 位,而之前您正在编译 32 位。

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

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

相反,您将指针投射到DWORDDWORD 始终是 32 位无符号类型,因此在为 32 位 Windows 构建时,一切顺利(指针需要不超过 32 位才能完好无损地到达另一侧),但在 64 位 Windows 上,您将丢失前 32 位你的指针。

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

正如 cmets 中所解释的,此指针来自堆,默认情况下,在 Windows 7 上,堆从 64 位地址空间的“低”部分开始提供内存;因此,除非您消耗大量内存,否则您将始终获得前 32 位为 0 的地址,因此即使前 32 位被切断,它们也将继续存在。

This changed since Windows 8,因为 ASLR(在构建 64 位可执行文件时由链接器默认启用)随机化堆在虚拟地址空间中的位置,这意味着您将获得高 32 位非零的指针,这将被DWORD的演员严重破坏。

长话短说:修复你的演员表1,一切都会好起来的。另外,以后要时刻警惕从指针到不以_ptr_PTR 结尾的整数类型的强制转换——你很有可能犯了错误。


备注

  1. 严格来说,IIRC 标准要求“通过”void * 才能使这些转换正常工作,即仅保证 uintptr_t 往返检查标准),所以它应该是(ULONG_PTR)(LPVOID)pContext,如果pContext 还不是void *。但是,这是 Win32,我很确定即使没有额外的演员表,它也能保证工作。

【讨论】:

  • DWORD 始终是 32 位无符号类型,因此在为 32 位 Windows 构建时一切顺利(指针需要不超过 32 位才能完好无损地到达另一侧),但在 64 位 Windows 上,您正在丢失指针的前 32 位。 >>>> 当为 Windows 7 64 位操作系统构建时,DWORD 使用工作正常。但是使用 DWORD 的 Windows 10 64 位应用程序在运行时崩溃了。
  • @Nithinsriparambudur:这只是运气;可能在 Windows 7 上,您传递的指针碰巧所有的最高位都为零,所以它工作正常。该指针指向哪里 - 堆栈、堆、全局变量?
  • @Nithinsriparambudur: this is quite precisely your case;从 Windows 8 开始,虚拟地址空间中的堆位置是随机的,因此从虚拟地址空间的 32 位部分之外的堆开始方式获取分配是正常的。
猜你喜欢
  • 2020-05-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-03-11
  • 2011-11-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多