我是C ++的新手,我试图构建一个小型的旧类库,该类库我一直用作x64的x86。
现在,编译器显示一些警告:
IUnknown* _p;
// warning C4311: 'type cast': pointer truncation from 'IUnknown *' to 'int'
// warning C4302: 'type cast': truncation from 'IUnknown *' to 'int'
virtual int GetHashCode() override
{
return (int)_p;
}
// 1> warning C4311: 'type cast': pointer truncation from 'void *' to 'long'
// 1> warning C4302: 'type cast': truncation from 'void *' to 'long'
void MyMethod(IntPtr hwnd, String^ str)
{
CComBSTR bstrValue = (BSTR)Marshal::StringToBSTR(str).ToPointer();
HRESULT result = SomeClass()->SomeMethod((long)hwnd.ToPointer(), bstrValue);
}
其中SomeMethod定义为
#ifdef _X86_
typedef long CUSTOMHWND;
#else
typedef LONGLONG CUSTOMHWND;
#endif
virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE SomeMethod(
/* [in] */ CUSTOMHWND hwndOwner,
/* [in] */ __RPC__in BSTR pValue) = 0;
我如何更改代码以使其x64安全?
答案 0 :(得分:1)
https://docs.microsoft.com/en-us/cpp/build/common-visual-cpp-64-bit-migration-issues?view=vs-2019
更多迁移技巧:https://docs.microsoft.com/en-us/windows/desktop/WinProg64/migration-tips
答案 1 :(得分:1)
通常,基于[expr.cast]/4的C样式是
return (int)_p;
最终将执行
return reinterpret_cast<int>(_p);
现在,严格来说,我认为这种情况下的行为实际上是不确定的。根据{{3}}:
可以将指针显式转换为足够大的整数类型,以容纳其类型的所有值。
请注意,此标准仅在将指针值强制转换为足够容纳该指针类型的任何可能值的整数类型的情况下指定行为。我不知道标准中的任何措辞会指定将指针值强制转换为太小的整数类型的情况下的行为,这是您在此处有效执行的操作,因为int
不大(在MSVC上)足以表示一个64位对象指针值。实际上,我听说过的任何编译器都只会生成返回int
包含的地址的低32位(假设_p
为32位宽)的代码,但是您很可能不应该这样做不用依靠。
通常,如果可以的话,我只会避免将指针转换为整数。如果确实需要,请确保使用足够大的整数类型来容纳指针值。在这种情况下,std::intptr_t
或std::uintptr_t
将是我的首选。
说了这么多,函数的名称将表明它仅应返回一个哈希值,大概是在哈希表中标识某些对象。如果这是目标,我建议您只使用[expr.reinterpret.cast]/4为您计算这样的哈希值,而不要自己依靠将指针强制转换为整数值:
virtual std::size_t GetHashCode() override
{
return std::hash<IUnknown*>{}(_p);
}
让std::hash
为您获取地址的哈希值。无论目标平台是什么,您都可以依靠始终执行正确的操作来获得这样的哈希值。