通过 void* 进行转换,而不是使用 reinterpret_cast
我正在读一本书,我发现不应该直接使用 reinterpret_cast
,而是将转换为 void* 与 static_cast
结合使用:
I'm reading a book and I found that reinterpret_cast
should not be used directly, but rather casting to void* in combination with static_cast
:
T1 * p1=...
void *pv=p1;
T2 * p2= static_cast<T2*>(pv);
代替:
T1 * p1=...
T2 * p2= reinterpret_cast<T2*>(p1);
然而,我找不到解释为什么这比直接演员更好.如果有人能给我一个解释或指出我的答案,我将不胜感激.
However, I can't find an explanation why is this better than the direct cast. I would very appreciate if someone can give me an explanation or point me to the answer.
提前致谢
附言我知道 reinterpret_cast
用于什么,但我从未见过以这种方式使用
p.s. I know what is reinterpret_cast
used for, but I never saw that is used in this way
推荐答案
对于允许此类转换的类型(例如,如果 T1
是 POD 类型且 T2
是 unsigned char
),使用 static_cast
的方法在标准中有明确定义.
For types for which such cast is permitted (e.g. if T1
is a POD-type and T2
is unsigned char
), the approach with static_cast
is well-defined by the Standard.
另一方面,reinterpret_cast
完全是实现定义的――你得到的唯一保证是你可以将指针类型转换为任何其他指针类型,然后返回,然后你会得到原始值;而且,您可以将指针类型转换为足够大的整数类型以保存指针值(这取决于实现,并且根本不需要存在),然后将其转换回来,您将获得原始值.
On the other hand, reinterpret_cast
is entirely implementation-defined - the only guarantee that you get for it is that you can cast a pointer type to any other pointer type and then back, and you'll get the original value; and also, you can cast a pointer type to an integral type large enough to hold a pointer value (which varies depending on implementation, and needs not exist at all), and then cast it back, and you'll get the original value.
更具体地说,我将引用标准的相关部分,突出重要部分:
To be more specific, I'll just quote the relevant parts of the Standard, highlighting important parts:
5.2.10[expr.reinterpret.cast]:
5.2.10[expr.reinterpret.cast]:
reinterpret_cast 执行的映射是实现定义的.[注意:它可能会,也可能不会,产生与原始值不同的表示.] ...指向对象的指针可以显式转换为指向不同类型对象的指针.)除了转换类型的右值指向 T1 的指针"指向类型指向 T2 的指针"(其中 T1 和 T2 是对象类型,其中 T2 的对齐要求不比 T1 严格)并返回其原始类型产生原始指针值,这种指针转换的结果是不确定的.
The mapping performed by reinterpret_cast is implementation-defined. [Note: it might, or might not, produce a representation different from the original value.] ... A pointer to an object can be explicitly converted to a pointer to an object of different type.) Except that converting an rvalue of type "pointer to T1" to the type "pointer to T2" (where T1 and T2 are object types and where the alignment requirements of T2 are no stricter than those of T1) and back to its original type yields the original pointer value, the result of such a pointer conversion is unspecified.
就像这样:
struct pod_t { int x; };
pod_t pod;
char* p = reinterpret_cast<char*>(&pod);
memset(p, 0, sizeof pod);
实际上是未指定的.
解释为什么 static_cast
起作用有点棘手.这是上面重写的代码以使用 static_cast
,我相信它可以保证始终按照标准的预期工作:
Explaining why static_cast
works is a bit more tricky. Here's the above code rewritten to use static_cast
which I believe is guaranteed to always work as intended by the Standard:
struct pod_t { int x; };
pod_t pod;
char* p = static_cast<char*>(static_cast<void*>(&pod));
memset(p, 0, sizeof pod);
再次,让我引用标准中的部分,这些部分共同使我得出结论,上述内容应该是可移植的:
Again, let me quote the sections of the Standard that, together, lead me to conclude that the above should be portable:
3.9[basic.types]:
3.9[basic.types]:
对于 POD 类型 T 的任何对象(除基类子对象外),无论该对象是否持有 T 类型的有效值,构成该对象的底层字节 (1.7) 都可以复制到字符或无符号字符.如果将 char 或 unsigned char 数组的内容复制回对象,则该对象随后将保持其原始值.
For any object (other than a base-class subobject) of POD type T, whether or not the object holds a valid value of type T, the underlying bytes (1.7) making up the object can be copied into an array of char or unsigned char. If the content of the array of char or unsigned char is copied back into the object, the object shall subsequently hold its original value.
T 类型对象的对象表示是 T 类型对象占用的 N 个 unsigned char 对象 的序列,其中 N 等于 sizeof(T).
The object representation of an object of type T is the sequence of N unsigned char objects taken up by the object of type T, where N equals sizeof(T).
3.9.2[basic.compound]:
3.9.2[basic.compound]:
cv-qualified (3.9.3) 或 cv-unqualified 类型的对象 void*
(指向 void 的指针),可用于指向未知类型的对象.void*
应该能够保存任何对象指针.cv-qualified 或 cv-unqualified (3.9.3) void*
应与 cv-qualified 或 cv-unqualified char*
具有相同的表示和对齐要求>.
Objects of cv-qualified (3.9.3) or cv-unqualified type
void*
(pointer to void), can be used to point to objects of unknown type. Avoid*
shall be able to hold any object pointer. A cv-qualified or cv-unqualified (3.9.3)void*
shall have the same representation and alignment requirements as a cv-qualified or cv-unqualifiedchar*
.
3.10[basic.lval]:
3.10[basic.lval]:
如果程序尝试通过以下类型之一以外的左值访问对象的存储值,则行为未定义):
If a program attempts to access the stored value of an object through an lvalue of other than one of the following types the behavior is undefined):
- ...
- 字符或无符号字符类型.
4.10[conv.ptr]:
4.10[conv.ptr]:
指向 cv T 的指针"类型的右值(其中 T 是对象类型)可以转换为指向 cv void 的指针"类型的右值.将指向 cv T 的指针"转换为指向 cv void 的指针"的结果指向类型 T 的对象所在的存储位置的开头,就好像该对象是类型 T 的最派生对象 (1.8)(即,不是基类子对象).
An rvalue of type "pointer to cv T," where T is an object type, can be converted to an rvalue of type "pointer to cv void." The result of converting a "pointer to cv T" to a "pointer to cv void" points to the start of the storage location where the object of type T resides, as if the object is a most derived object (1.8) of type T (that is, not a base class subobject).
5.2.9[expr.static.cast]:
5.2.9[expr.static.cast]:
任何标准转换序列(第 4 条)的逆,除了左值到右值 (4.1)、数组到指针 (4.2)、函数到指针 (4.3) 和布尔 (4.12) 转换,可以使用 static_cast 显式执行.
The inverse of any standard conversion sequence (clause 4), other than the lvalue-to-rvalue (4.1), array-topointer (4.2), function-to-pointer (4.3), and boolean (4.12) conversions, can be performed explicitly using static_cast.
另一方面,我们有这个宝石:
On the other hand, we have this gem:
9.2[class.mem]/17:
9.2[class.mem]/17:
指向 POD 结构对象的指针,使用 reinterpret_cast 进行适当转换,指向其初始成员(或者如果该成员是位域,则指向它所在的单元),反之亦然.[注意:POD 结构对象中可能因此有未命名的填充,但不是在其开头,这是实现适当对齐所必需的.]
A pointer to a POD-struct object, suitably converted using a reinterpret_cast, points to its initial member (or if that member is a bit-field, then to the unit in which it resides) and vice versa. [Note: There might therefore be unnamed padding within a POD-struct object, but not at its beginning, as necessary to achieve appropriate alignment. ]
这似乎暗示指针之间的 reinterpret_cast
以某种方式暗示相同的地址".去搞清楚.
which seems to imply that reinterpret_cast
between pointers somehow implies "same address". Go figure.
相关文章