C++ 我应该使用它还是静态_cast<;无效*>;然后静态_cast<;myType*>;为了避免重新解释?
我曾看到有人建议使用C++ 我应该使用它还是静态_cast<;无效*>;然后静态_cast<;myType*>;为了避免重新解释?,c++,casting,reinterpret-cast,static-cast,C++,Casting,Reinterpret Cast,Static Cast,我曾看到有人建议使用static\u cast(static\u cast(p))而不是重新解释cast 我不明白为什么这样更好,有人能解释一下吗 为了便于讨论,这里有一个需要重新解释的示例场景: DWORD lpNumberOfBytes; ULONG_PTR lpCompletionKey; LPOVERLAPPED lpOverlapped; GetQueuedCompletionStatus(myHandle, &lpNumberOfBytes, &lpCompletio
static\u cast(static\u cast(p))
而不是重新解释cast
我不明白为什么这样更好,有人能解释一下吗
为了便于讨论,这里有一个需要重新解释的示例场景:
DWORD lpNumberOfBytes;
ULONG_PTR lpCompletionKey;
LPOVERLAPPED lpOverlapped;
GetQueuedCompletionStatus(myHandle, &lpNumberOfBytes, &lpCompletionKey, &lpOverlapped, 0);
if(lpCompletionKey == myCustomHandlerKey){
auto myObject = reinterpret_cast<MyObject*>(lpOverlapped); //i know this is really a MyObject
}
DWORD lpNumberOfBytes;
ULONG_PTR lpCompletionKey;
lp重叠lp重叠;
GetQueuedCompletionStatus(myHandle,&lpNumberOfBytes,&lpCompletionKey,&lpOverlapped,0);
如果(lpCompletionKey==myCustomHandlerKey){
auto myObject=reinterpret_cast(lpOverlapped);//我知道这确实是一个myObject
}
这就是我听到的建议:
auto myObject = static_cast<MyObject*>(static_cast<void*>(lpOverlapped));
auto myObject=static_cast(static_cast(lpOverlapped));
编辑:我最初是从评论部分开始提问的,“asdf”建议在此处使用静态转换而不是重新解释转换,但回想起来,我的问题来自于此并不相关。§5.2.10描述了
重新解释转换
可以执行的法律映射,并指定“无法执行其他转换”
与您的示例相关的转换为/7:
指向对象的指针可以显式转换为指向不同对象类型的指针。当类型为“指针指向T1
”的prvaluev
转换为类型为“指针指向cvT2
”时,结果是static\u cast(static\u cast(v))
如果T1
和T2
都是标准布局类型,T2
的对齐要求并不比T1
的对齐要求更严格。[强调]
任何其他指向对象类型的指针的转换结果为“未指定”。1
这是reinterpret\u cast
危险的两个原因之一:它的转换只针对指向对象类型的指针子集定义良好,编译器通常不提供关于意外误用的诊断
第二个原因是编译器甚至不会首先检查您尝试执行的映射是否合法,以及要执行的许多(语义完全不同)映射中的哪一个
最好是明确地告诉编译器(和读者)也就是说,asdf的评论并不完全正确,因为并非所有您可能希望通过reinterpret\u cast
执行的转换都等同于使用static\u cast
然后对目标类型执行static\u cast
1旁白:简而言之(稍微简化),a是一个类型(或类型数组)它没有虚拟函数或混合成员可见性,并且它的所有成员和基也是标准布局。类型的类型限制了它可能位于的内存中的地址。例如,许多机器要求将双精度对齐到可被8整除的地址。
asdf
对此进行了解释很好,即使在链接的帖子中简洁地说
因为编译器不知道CustomImage是从
这是程序中的一点
就我个人而言,我不会费心从msdn下载垃圾,只是为了深入研究并回答这个问题。毕竟这是一个编码挑战,你应该弄清楚它
<>我在C++中的铸造规则是:
T*obj=。。。;
void*tmp=重新解释铸造对象;
T*ref=reinterpret\u cast tmp;//T*obj-->T*ref
在这里,您必须确保
obj
和ref
是相同的精确类型,包括常量限定符、类派生、对齐、内存类型(嵌入式),绝对是你能想到的任何东西。reinterpret\u cast几乎总是实现定义的,发生的事情并不总是保证可移植的。@Plasmah这有点误导。reinterpret\u cast
有非常好的定义语义,它们只是非常有限。但在这种情况下,语义似乎被覆盖了(根据OP的声明,lpOverlapped
),我在没有看代码的情况下这么说。但是阅读asdf的注释是完全不同的情况。当您从一个指针类型强制转换到另一个指针类型时,reinterpret\u cast
是根据静态强制转换(静态强制转换(p))来指定的
在C++11中。它们都是相同的。另一方面,如果您想确保转换是安全的,可以使用,然后使用指针强制转换(lpOverlapped)
+1用于引用标准和解释最重要的部分…如果你这样做了,我会给+2用于列出和解释所有的个人要求,如果我可以的话。你看,甚至我在我的回答中忘记了对齐。双静态\u cast
是在定义reinterptret和标识双cast的情况之外定义的吗?@Yakk我不太清楚你的意思,但如果我理解正确的话,双static\u cast
via
void*`比reinterpret\u cast
更具限制性,而不是更一般性。这就是为什么选择它的原因:它的语义因此更清晰。@Konradulphreinterpret\u cast
说“如果是条件,那么它相当于static\u cast(X))
”现在,如果其中一个条件,或者X
是T*
(即使条件不成立),那么如果显式写出,该双-static\u cast
,则是有效的.还有其他情况下,双静态强制转换会导致定义的行为吗?@Yakk说实话,我不知道。在阅读之前
T* obj = ...;
void* tmp = reinterpret_cast<void*> obj;
T* ref = reinterpret_cast<T*> tmp; // T* obj --> T* ref