有关"警告C4312:'type cast'"的问题

Tob*_*bbe 8 c++ 64-bit winapi

这是我的代码:

HWND WebformCreate(HWND hParent, UINT id)
{
    return CreateWindowEx(0, WEBFORM_CLASS, _T("about:blank"),
        WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE, 0, 0, 100, 100, hParent,
        (HMENU)id, GetModuleHandle(NULL), 0);
}
Run Code Online (Sandbox Code Playgroud)

这是我收到的警告:

warning C4312: 'type cast' : conversion from 'UINT' to 'HMENU' of greater size
Run Code Online (Sandbox Code Playgroud)

这些是我的问题:

  1. 为什么编译器认为转换为更大的类型是个坏主意?
  2. 什么是摆脱警告的最佳方法?(我不想禁用它.)
  3. 像这样做双重类型转换:(HMENU)(UINT_PTR)id摆脱警告.为什么/怎么样?
  4. 禁用"检测64位可移植性问题"(Wp64)也会消除警告.为什么弃用Wp64?我可以买吗?

AnT*_*AnT 14

隐藏在HMENU名称后面的类型实际上是指针类型.编译器告诉你,将较小的整数类型包含在较大的指针类型中是没有意义的,因为结果指针值将是"不完整的",即如果指针值将用零填充则为高位.后者对指针类型没什么意义.

在您的特定情况下,这是安全的,因为这个HMENU值实际上不应该是指向任何地方的指针.但是,编译器不知道,这就是它发出警告的原因.在演员表中使用一个更大的整数类型作为中间类型,警告将消失(你建议你自己),因为在这种情况下你做两个演员:小整数到一个更大的整数,然后更大的整数到指针.较小的整数到一个较大的整数是一个算术运算,对于它来说,用零填充高阶位是很有意义的(所表示的值不会改变),因此不会有任何警告.

  • 感谢您对双重演员为何有效的出色解释! (2认同)

Pup*_*ppy 4

您正在将 32 位 UINT 转换为 64 位指针。那是自杀——你试图指向某样东西,但却忘记了一半的位置!你绝对必须采用 UINT_PTR。当您将指针强制转换为 int 时,只有当 int 的大小与指针的大小相同时,该行为才正常。否则,应用程序的运行时会因访问冲突而结束。

编辑:
为什么编译器认为转换为更大的类型是一个坏主意?
正上方

摆脱警告的最佳方法是什么?(我不想禁用它。)
解决问题。这段代码几乎肯定会崩溃。

执行如下所示的双精度类型转换: (HMENU)(UINT_PTR)id 可以消除警告。为什么/如何?
发生这种情况是因为将 UINT 转换为 UINT_PTR 是完全有效的 - UINT_PTR 只是整数类型,不会丢失数据。

禁用“检测 64 位可移植性问题”(Wp64) 也可以消除该警告。为什么 Wp64 被弃用?我应该戴上它吗?
它已被弃用,因为实际上我不太记得为什么。我认为它发出警告有点太容易了。但对于基本的“不要强制转换整型类型和指针”,您绝对应该保留它。

  • @DeadMG:不正确。该代码不会崩溃,因为从 WinAPI 的角度来看,代码中的转换是完全安全且正确的。当您创建`WS_CHILD`样式的窗口时,您必须将子窗口的ID传递给`HMENU`类型。这就是 WinAPI 中的工作原理。它不是“菜单的句柄”。如果窗口不是“WS_CHILD”,它将是“菜单句柄”。 (8认同)
  • 该代码按原样工作正常。没有崩溃。从 msdn 复制/粘贴:“对于子窗口,hMenu 指定子窗口标识符,这是对话框控件用来通知其父级有关事件的整数值。” (5认同)