266 lines
48 KiB
HTML
266 lines
48 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="zh" dir="ltr" class="client-nojs" xmlns="http://www.w3.org/1999/xhtml" xml:lang="zh">
|
|
<head><meta http-equiv="x-ua-compatible" content="ie=edge">
|
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
|
<title>reinterpret_cast 转换</title>
|
|
<link rel="stylesheet" href="ext.css" />
|
|
<link rel="stylesheet" href="site_modules.css" />
|
|
</head>
|
|
<body class="mediawiki ltr sitedir-ltr ns-0 ns-subject page-cpp_language_reinterpret_cast skin-cppreference2 action-view cpp-navbar">
|
|
<div id="cpp-content-base">
|
|
<div id="content"><a id="top"></a>
|
|
<h1 id="firstHeading" class="firstHeading">reinterpret_cast 转换</h1>
|
|
<div id="bodyContent">
|
|
<div id="contentSub"><span class="subpages">< <a href="cpp.html">cpp</a>‎ | <a href="cpp-language.html">language</a></span></div>
|
|
<div id="mw-content-text" lang="zh" dir="ltr" class="mw-content-ltr" xml:lang="zh">
|
|
<p>通过重新解释底层位模式在类型间转换。</p>
|
|
<h3><span class="mw-headline" id=".E8.AF.AD.E6.B3.95">语法</span></h3>
|
|
<table class="t-sdsc-begin">
|
|
<tr>
|
|
<td colspan="10" class="t-sdsc-sep"></td>
|
|
</tr>
|
|
<tr class="t-sdsc">
|
|
<td class="t-sdsc-nopad"><code><b>reinterpret_cast <</b></code> <span class="t-spar">新类型</span> <code><b>> (</b></code> <span class="t-spar">表达式</span> <code><b>)</b></code></td>
|
|
<td class="t-sdsc-nopad"></td>
|
|
<td class="t-sdsc-nopad"></td>
|
|
</tr>
|
|
<tr>
|
|
<td colspan="10" class="t-sdsc-sep"></td>
|
|
</tr>
|
|
</table>
|
|
<p>返回 <span class="t-spar">新类型</span> 类型的值。</p>
|
|
<h3><span class="mw-headline" id=".E8.A7.A3.E9.87.8A">解释</span></h3>
|
|
<p>与 <span class="t-c"><span class="mw-geshi cpp source-cpp"><span class="kw1">static_cast</span></span></span> 不同,但与 <span class="t-c"><span class="mw-geshi cpp source-cpp"><span class="kw1">const_cast</span></span></span> 类似,<span class="t-c"><span class="mw-geshi cpp source-cpp"><span class="kw1">reinterpret_cast</span></span></span> 表达式不会编译成任何 CPU 指令(除非在整数和指针间转换,或在指针表示依赖其类型的不明架构上)。它纯粹是一个编译时指令,指示编译器将 <span class="t-spar">表达式</span> 视为如同具有 <span class="t-spar">新类型</span> 类型一样处理。</p>
|
|
<p>只有下列转换在不去除<i>常量性</i>或<i>易变性</i>的场合才能用 <span class="t-c"><span class="mw-geshi cpp source-cpp"><span class="kw1">reinterpret_cast</span></span></span> 执行。</p>
|
|
<div class="t-li1"><span class="t-li">1)</span> 整型、枚举、指针或成员指针类型的表达式可转换到其自身的类型。产生的值与 <span class="t-spar">表达式</span> 的相同。<span class="t-mark-rev t-since-cxx11">(C++11 起)</span></div>
|
|
<div class="t-li1"><span class="t-li">2)</span> 指针能转换成大小足以保有其类型所有值的任何整型类型(例如转换成 <span class="t-lc"><a href="cpp-types-integer.html">std::uintptr_t</a></span>)</div>
|
|
<div class="t-li1"><span class="t-li">3)</span> 任何整型或枚举类型的值可转换到指针类型。指针转换到有足够大小的整数再转换回同一指针类型后,保证拥有其原值,否则结果指针无法安全地解引用(不保证相反方向的往返转换;相同指针可拥有多种整数表示)。不保证空指针常量 <span class="t-lc"><a href="cpp-types-NULL.html">NULL</a></span> 或整数零生成目标类型的空指针值;此时应该用 <a href="cpp-language-static_cast.html">static_cast</a> 或<a href="cpp-language-implicit_conversion.html">隐式转换</a>。</div>
|
|
<div class="t-li1"><span class="t-li">4)</span> 任何 <span class="t-lc"><a href="cpp-types-nullptr_t.html">std::nullptr_t</a></span> 类型的值,包含 <span class="t-c"><span class="mw-geshi cpp source-cpp">nullptr</span></span>,可转换成任何整型类型,如同它是 <span class="t-c"><span class="mw-geshi cpp source-cpp"><span class="br0">(</span><span class="kw4">void</span><span class="sy2">*</span><span class="br0">)</span><span class="nu0">0</span></span></span> 一样。但没有值能转换成 <span class="t-lc"><a href="cpp-types-nullptr_t.html">std::nullptr_t</a></span>,甚至 <span class="t-c"><span class="mw-geshi cpp source-cpp">nullptr</span></span> 也不行:此时应该用 <span class="t-c"><span class="mw-geshi cpp source-cpp"><span class="kw1">static_cast</span></span></span>。<span class="t-mark-rev t-since-cxx11">(C++11 起)</span></div>
|
|
<div class="t-li1"><span class="t-li">5)</span> 任何对象指针类型 <code>T1*</code> 可转换成指向对象指针类型 <code><i>cv</i> T2*</code> 。这严格等价于 <span class="t-c"><span class="mw-geshi cpp source-cpp"><span class="kw1">static_cast</span><span class="sy1"><</span>cv T2<span class="sy2">*</span><span class="sy1">></span><span class="br0">(</span><span class="kw1">static_cast</span><span class="sy1"><</span>cv <span class="kw4">void</span><span class="sy2">*</span><span class="sy1">></span><span class="br0">(</span>表达式<span class="br0">)</span><span class="br0">)</span></span></span>(这意味着,若 <code>T2</code> 的对齐要求不比 <code>T1</code> 的更严格,则指针值不改变,且将结果指针转换回原类型将生成其原值)。任何情况下,只有<i>类型别名化(type aliasing)</i>规则允许(见下文)时,结果指针才可以安全地解引用。</div>
|
|
<div class="t-li1"><span class="t-li">6)</span> <code>T1</code> 类型的左值表达式可转换成到另一个类型 <code>T2</code> 的引用。结果是与原左值指代同一对象,但有不同类型的左值或亡值。不创建临时量,不进行复制,不调用构造函数或转换函数。只有<i>类型别名化(type aliasing)</i>规则允许(见下文)时,结果引用才可以安全访问。</div>
|
|
<div class="t-li1"><span class="t-li">7)</span> 任何函数指针可转换成指向不同函数类型的指针。通过指向不同函数类型的指针调用函数是未定义的,但将这种指针转换回指向原函数类型的指针将生成指向原函数的指针值。</div>
|
|
<div class="t-li1"><span class="t-li">8)</span> 一些实现上(特别是在任何 POSIX 兼容的系统上,即基于 <a rel="nofollow" class="external text" href="http://pubs.opengroup.org/onlinepubs/9699919799/functions/dlsym.html">dlsym</a> 的要求),函数指针可以转换成 <span class="t-c"><span class="mw-geshi cpp source-cpp"><span class="kw4">void</span><span class="sy2">*</span></span></span> 或任何其他对象指针,反之亦然。若实现支持双向的转换,则转换回原类型将生成原值,否则结果指针不能安全地解引用或调用。</div>
|
|
<div class="t-li1"><span class="t-li">9)</span> 任何指针类型的空指针值可转换成任何其他指针类型,产生该类型的空指针值。注意不能用 <span class="t-c"><span class="mw-geshi cpp source-cpp"><span class="kw1">reinterpret_cast</span></span></span> 将空指针常量 <span class="t-c"><span class="mw-geshi cpp source-cpp">nullptr</span></span> 或任何其他 <span class="t-lc"><a href="cpp-types-nullptr_t.html">std::nullptr_t</a></span> 类型的值转换为指针:此时应该使用隐式转换或 <span class="t-c"><span class="mw-geshi cpp source-cpp"><span class="kw1">static_cast</span></span></span>。</div>
|
|
<div class="t-li1"><span class="t-li">10)</span> 成员函数指针可转换成指向不同类型的不同成员函数的指针。转换回原类型将生成原值,否则结果指针不能安全使用。</div>
|
|
<div class="t-li1"><span class="t-li">11)</span> 指向某类 <code>T1</code> 的成员对象的指针可转换成指向另一个类 <code>T2</code> 的另一个成员对象的指针。若 <code>T2</code> 的对齐不比 <code>T1</code> 更严格,则转换回原类型 <code>T1</code> 将生成原值,否则不能安全地使用结果指针。</div>
|
|
<p>同所有转型表达式,结果是:</p>
|
|
<ul>
|
|
<li>左值,如果 <span class="t-spar">新类型</span> 是左值引用或到函数类型的右值引用;</li>
|
|
<li>亡值,如果 <span class="t-spar">新类型</span> 是到对象类型的右值引用;</li>
|
|
<li>否则为纯右值。</li>
|
|
</ul>
|
|
<h3><span class="mw-headline" id=".E5.85.B3.E9.94.AE.E8.AF.8D">关键词</span></h3>
|
|
<p><a href="cpp-keyword-reinterpret_cast.html"><tt>reinterpret_cast</tt></a></p>
|
|
<h3><span class="mw-headline" id=".E7.B1.BB.E5.9E.8B.E5.88.AB.E5.90.8D.E5.8C.96">类型别名化</span></h3>
|
|
<p>如果下列条件均不满足,每当试图通过 <code>别名类型</code> 类型的泛左值读或修改类型为 <code>动态类型</code> 的对象的值时,行为未定义:</p>
|
|
<ul>
|
|
<li><code>别名类型</code> 与 <code>动态类型</code> <i>相似</i>。</li>
|
|
<li><code>别名类型</code> 是 <code>动态类型</code> 的(可有 <a href="cpp-language-cv.html">cv</a> 限定的)有符号或无符号变体。</li>
|
|
<li><code>别名类型</code> 为 <span class="t-rev-inl t-since-cxx17"><span><a href="cpp-types-byte.html"><tt>std::byte</tt></a>、</span> <span><span class="t-mark-rev t-since-cxx17">(C++17 起)</span></span></span><span class="t-c"><span class="mw-geshi cpp source-cpp"><span class="kw4">char</span></span></span> 或 <span class="t-c"><span class="mw-geshi cpp source-cpp"><span class="kw4">unsigned</span> <span class="kw4">char</span></span></span>:这容许将任何对象的<a href="cpp-language-object.html#.E5.AF.B9.E8.B1.A1.E8.A1.A8.E7.A4.BA.E4.B8.8E.E5.80.BC.E8.A1.A8.E7.A4.BA">对象表示</a>作为一个字节数组加以检验。</li>
|
|
</ul>
|
|
<p>非正式地说,忽略顶层 cv 限定性,若两个类型符合下列条件,则它们<i>相似</i>:</p>
|
|
<ul>
|
|
<li>它们是同一类型;或</li>
|
|
<li>它们都是指针,且被指向的类型相似;或</li>
|
|
<li>它们都是指向相同类的成员指针,且被指向的成员类型相似;或</li>
|
|
</ul>
|
|
<table class="t-rev-begin">
|
|
<tr class="t-rev t-until-cxx20">
|
|
<td>
|
|
<ul>
|
|
<li>它们都是大小相同的数组或都是未知边界数组,且数组元素类型相似。</li>
|
|
</ul>
|
|
</td>
|
|
<td><span class="t-mark-rev t-until-cxx20">(C++20 前)</span></td>
|
|
</tr>
|
|
<tr class="t-rev t-since-cxx20">
|
|
<td>
|
|
<ul>
|
|
<li>它们都是数组,大小相同或至少一个是未知边界数组,且数组元素类型相似。</li>
|
|
</ul>
|
|
</td>
|
|
<td><span class="t-mark-rev t-since-cxx20">(C++20 起)</span></td>
|
|
</tr>
|
|
</table>
|
|
<p>例如:</p>
|
|
<ul>
|
|
<li><span class="t-c"><span class="mw-geshi cpp source-cpp"><span class="kw4">const</span> <span class="kw4">int</span> <span class="sy2">*</span> <span class="kw4">volatile</span> <span class="sy2">*</span></span></span> 与 <span class="t-c"><span class="mw-geshi cpp source-cpp"><span class="kw4">int</span> <span class="sy2">*</span> <span class="sy2">*</span> <span class="kw4">const</span></span></span> 相似;</li>
|
|
<li><span class="t-c"><span class="mw-geshi cpp source-cpp"><span class="kw4">const</span> <span class="kw4">int</span> <span class="br0">(</span><span class="sy2">*</span> <span class="kw4">volatile</span> S<span class="sy4">::</span><span class="sy2">*</span> <span class="kw4">const</span><span class="br0">)</span><span class="br0">[</span><span class="nu0">20</span><span class="br0">]</span></span></span> 与 <span class="t-c"><span class="mw-geshi cpp source-cpp"><span class="kw4">int</span> <span class="br0">(</span><span class="sy2">*</span> <span class="kw4">const</span> S<span class="sy4">::</span><span class="sy2">*</span> <span class="kw4">volatile</span><span class="br0">)</span><span class="br0">[</span><span class="nu0">20</span><span class="br0">]</span></span></span> 相似;</li>
|
|
<li><span class="t-c"><span class="mw-geshi cpp source-cpp"><span class="kw4">int</span> <span class="br0">(</span><span class="sy2">*</span> <span class="kw4">const</span> <span class="sy2">*</span><span class="br0">)</span><span class="br0">(</span><span class="kw4">int</span> <span class="sy2">*</span><span class="br0">)</span></span></span> 与 <span class="t-c"><span class="mw-geshi cpp source-cpp"><span class="kw4">int</span> <span class="br0">(</span><span class="sy2">*</span> <span class="kw4">volatile</span> <span class="sy2">*</span><span class="br0">)</span><span class="br0">(</span><span class="kw4">int</span> <span class="sy2">*</span><span class="br0">)</span></span></span> 相似;</li>
|
|
<li><span class="t-c"><span class="mw-geshi cpp source-cpp"><span class="kw4">int</span> <span class="br0">(</span>S<span class="sy4">::</span><span class="sy2">*</span><span class="br0">)</span><span class="br0">(</span><span class="br0">)</span> <span class="kw4">const</span></span></span> 与 <span class="t-c"><span class="mw-geshi cpp source-cpp"><span class="kw4">int</span> <span class="br0">(</span>S<span class="sy4">::</span><span class="sy2">*</span><span class="br0">)</span><span class="br0">(</span><span class="br0">)</span></span></span> <i>不</i>相似;</li>
|
|
<li><span class="t-c"><span class="mw-geshi cpp source-cpp"><span class="kw4">int</span> <span class="br0">(</span><span class="sy2">*</span><span class="br0">)</span><span class="br0">(</span><span class="kw4">int</span> <span class="sy2">*</span><span class="br0">)</span></span></span> 与 <span class="t-c"><span class="mw-geshi cpp source-cpp"><span class="kw4">int</span> <span class="br0">(</span><span class="sy2">*</span><span class="br0">)</span><span class="br0">(</span><span class="kw4">const</span> <span class="kw4">int</span> <span class="sy2">*</span><span class="br0">)</span></span></span> <i>不</i>相似;</li>
|
|
<li><span class="t-c"><span class="mw-geshi cpp source-cpp"><span class="kw4">const</span> <span class="kw4">int</span> <span class="br0">(</span><span class="sy2">*</span><span class="br0">)</span><span class="br0">(</span><span class="kw4">int</span> <span class="sy2">*</span><span class="br0">)</span></span></span> 与 <span class="t-c"><span class="mw-geshi cpp source-cpp"><span class="kw4">int</span> <span class="br0">(</span><span class="sy2">*</span><span class="br0">)</span><span class="br0">(</span><span class="kw4">int</span> <span class="sy2">*</span><span class="br0">)</span></span></span> <i>不</i>相似;</li>
|
|
<li><span class="t-c"><span class="mw-geshi cpp source-cpp"><span class="kw4">int</span> <span class="br0">(</span><span class="sy2">*</span><span class="br0">)</span><span class="br0">(</span><span class="kw4">int</span> <span class="sy2">*</span> <span class="kw4">const</span><span class="br0">)</span></span></span> 与 <span class="t-c"><span class="mw-geshi cpp source-cpp"><span class="kw4">int</span> <span class="br0">(</span><span class="sy2">*</span><span class="br0">)</span><span class="br0">(</span><span class="kw4">int</span> <span class="sy2">*</span><span class="br0">)</span></span></span> 相似(它们是同一类型);</li>
|
|
<li><span class="t-c"><span class="mw-geshi cpp source-cpp"><a href="cpp-utility-pair.html"><span class="kw1096">std::<span class="me2">pair</span></span></a><span class="sy1"><</span><span class="kw4">int</span>, <span class="kw4">int</span><span class="sy1">></span></span></span> 与 <span class="t-c"><span class="mw-geshi cpp source-cpp"><a href="cpp-utility-pair.html"><span class="kw1096">std::<span class="me2">pair</span></span></a><span class="sy1"><</span><span class="kw4">const</span> <span class="kw4">int</span>, <span class="kw4">int</span><span class="sy1">></span></span></span> <i>不</i>相似。</li>
|
|
</ul>
|
|
<p>此规则允许进行基于类型的别名分析,即编译器假设通过一个类型的泛左值读取的值,不会被通过不同类型的泛左值的写入所修改(依据上述例外情况)。</p>
|
|
<p>注意,许多 C++ 编译器作为非标准语言扩展放松此规则,以允许通过 <a href="cpp-language-union.html">union</a> 的不活跃成员的进行类型错误的访问(这种访问在 C 中并不是未定义的)。</p>
|
|
<h3><span class="mw-headline" id=".E6.B3.A8.E8.A7.A3">注解</span></h3>
|
|
<p>标准中定义严格别名化规则的段落含有两条额外条例,部分从 C 继承而来:</p>
|
|
<ul>
|
|
<li><code>别名类型</code> 为<a href="cpp-language-aggregate_initialization.html">聚合类型</a>或 <a href="cpp-language-union.html">union</a> 类型,它保有前述各类型之一作为其元素或非静态成员(递归地包含子聚合体的元素和被包含的联合体的非静态数据成员)。</li>
|
|
<li><code>别名类型</code> 为 <code>动态类型</code> 的(可有 <a href="cpp-language-cv.html">cv</a> 限定的)<a href="cpp-language-derived_class.html">基类</a>。</li>
|
|
</ul>
|
|
<p>这些条例所描述的情况不可能出现于 C++,从而从上面的讨论中省略。在 C 中,聚合复制和赋值将聚合体对象作为整体访问。但 C++ 中始终通过成员函数调用进行这种行动,这会访问单独的子对象而非整个对象(或在联合体的情况下,复制对象表示,即经由 <span class="t-c"><span class="mw-geshi cpp source-cpp"><span class="kw4">unsigned</span> <span class="kw4">char</span></span></span>)。见<a rel="nofollow" class="external text" href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2051">核心问题 2051</a>。</p>
|
|
<p>假设符合对齐要求,则 <code>reinterpret_cast</code> 在处理<a href="cpp-language-static_cast.html#.E6.8C.87.E9.92.88.E5.8F.AF.E4.BA.92.E8.BD.AC.E6.8D.A2"><i>指针可互转换</i></a>对象的少数受限情况外,不更改<a href="cpp-language-pointer.html#.E6.8C.87.E9.92.88">指针的值</a>:</p>
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="cpp source-cpp">
|
|
<pre class="de1"><span class="kw1">struct</span> S1 <span class="br0">{</span> <span class="kw4">int</span> a<span class="sy4">;</span> <span class="br0">}</span> s1<span class="sy4">;</span>
|
|
<span class="kw1">struct</span> S2 <span class="br0">{</span> <span class="kw4">int</span> a<span class="sy4">;</span> <span class="kw1">private</span><span class="sy4">:</span> <span class="kw4">int</span> b<span class="sy4">;</span> <span class="br0">}</span> s2<span class="sy4">;</span> <span class="co1">// 非标准布局</span>
|
|
<span class="kw1">union</span> U <span class="br0">{</span> <span class="kw4">int</span> a<span class="sy4">;</span> <span class="kw4">double</span> b<span class="sy4">;</span> <span class="br0">}</span> u <span class="sy1">=</span> <span class="br0">{</span><span class="nu0">0</span><span class="br0">}</span><span class="sy4">;</span>
|
|
<span class="kw4">int</span> arr<span class="br0">[</span><span class="nu0">2</span><span class="br0">]</span><span class="sy4">;</span>
|
|
|
|
<span class="kw4">int</span><span class="sy2">*</span> p1 <span class="sy1">=</span> <span class="kw1">reinterpret_cast</span><span class="sy1"><</span><span class="kw4">int</span><span class="sy2">*</span><span class="sy1">></span><span class="br0">(</span><span class="sy3">&</span>s1<span class="br0">)</span><span class="sy4">;</span> <span class="co1">// p1 的值为“指向 s1.a 的指针”</span>
|
|
<span class="co1">// 因为 s1.a 与 s1 为指针可互转换</span>
|
|
|
|
<span class="kw4">int</span><span class="sy2">*</span> p2 <span class="sy1">=</span> <span class="kw1">reinterpret_cast</span><span class="sy1"><</span><span class="kw4">int</span><span class="sy2">*</span><span class="sy1">></span><span class="br0">(</span><span class="sy3">&</span>s2<span class="br0">)</span><span class="sy4">;</span> <span class="co1">// reinterpret_cast 不更改 p2 的值为“指向 s2 的指针”。 </span>
|
|
|
|
<span class="kw4">int</span><span class="sy2">*</span> p3 <span class="sy1">=</span> <span class="kw1">reinterpret_cast</span><span class="sy1"><</span><span class="kw4">int</span><span class="sy2">*</span><span class="sy1">></span><span class="br0">(</span><span class="sy3">&</span>u<span class="br0">)</span><span class="sy4">;</span> <span class="co1">// p3 的值为“指向 u.a 的指针”:u.a 与 u 指针可互转换</span>
|
|
|
|
<span class="kw4">double</span><span class="sy2">*</span> p4 <span class="sy1">=</span> <span class="kw1">reinterpret_cast</span><span class="sy1"><</span><span class="kw4">double</span><span class="sy2">*</span><span class="sy1">></span><span class="br0">(</span>p3<span class="br0">)</span><span class="sy4">;</span> <span class="co1">// p4 的指针为“指向 u.b 的指针”:u.a 与 u.b</span>
|
|
<span class="co1">// 指针可互转换,因为都与 u 指针可互转换</span>
|
|
|
|
<span class="kw4">int</span><span class="sy2">*</span> p5 <span class="sy1">=</span> <span class="kw1">reinterpret_cast</span><span class="sy1"><</span><span class="kw4">int</span><span class="sy2">*</span><span class="sy1">></span><span class="br0">(</span><span class="sy3">&</span>arr<span class="br0">)</span><span class="sy4">;</span> <span class="co1">// reinterpret_cast 不更改 p5 的值为“指向 arr 的指针”</span></pre></div>
|
|
</div>
|
|
<p>在不实际代表适当类型的对象的泛左值(例如通过 <code>reinterpret_cast</code> 所获得)上,进行代表非静态数据成员或非静态成员函数的成员访问,将导致未定义行为:</p>
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="cpp source-cpp">
|
|
<pre class="de1"><span class="kw1">struct</span> S <span class="br0">{</span> <span class="kw4">int</span> x<span class="sy4">;</span> <span class="br0">}</span><span class="sy4">;</span>
|
|
<span class="kw1">struct</span> T <span class="br0">{</span> <span class="kw4">int</span> x<span class="sy4">;</span> <span class="kw4">int</span> f<span class="br0">(</span><span class="br0">)</span><span class="sy4">;</span> <span class="br0">}</span><span class="sy4">;</span>
|
|
<span class="kw1">struct</span> S1 <span class="sy4">:</span> S <span class="br0">{</span><span class="br0">}</span><span class="sy4">;</span> <span class="co1">// 标准布局</span>
|
|
<span class="kw1">struct</span> ST <span class="sy4">:</span> S, T <span class="br0">{</span><span class="br0">}</span><span class="sy4">;</span> <span class="co1">// 非标准布局</span>
|
|
|
|
S s <span class="sy1">=</span> <span class="br0">{</span><span class="br0">}</span><span class="sy4">;</span>
|
|
<span class="kw4">auto</span> p <span class="sy1">=</span> <span class="kw1">reinterpret_cast</span><span class="sy1"><</span>T<span class="sy2">*</span><span class="sy1">></span><span class="br0">(</span><span class="sy3">&</span>s<span class="br0">)</span><span class="sy4">;</span> <span class="co1">// p 的值为“指向 s 的指针”</span>
|
|
<span class="kw4">auto</span> i <span class="sy1">=</span> p<span class="sy2">-</span><span class="sy1">></span>x<span class="sy4">;</span> <span class="co1">// 类成员访问表达式为未定义行为:s 不是 T 对象</span>
|
|
p<span class="sy2">-</span><span class="sy1">></span>x <span class="sy1">=</span> <span class="nu0">1</span><span class="sy4">;</span> <span class="co1">// 未定义行为</span>
|
|
p<span class="sy2">-</span><span class="sy1">></span>f<span class="br0">(</span><span class="br0">)</span><span class="sy4">;</span> <span class="co1">// 未定义行为</span>
|
|
|
|
S1 s1 <span class="sy1">=</span> <span class="br0">{</span><span class="br0">}</span><span class="sy4">;</span>
|
|
<span class="kw4">auto</span> p1 <span class="sy1">=</span> <span class="kw1">reinterpret_cast</span><span class="sy1"><</span>S<span class="sy2">*</span><span class="sy1">></span><span class="br0">(</span><span class="sy3">&</span>s1<span class="br0">)</span><span class="sy4">;</span> <span class="co1">// p1 的值为“指向 S 的 s1 子对象的指针”</span>
|
|
<span class="kw4">auto</span> i <span class="sy1">=</span> p1<span class="sy2">-</span><span class="sy1">></span>x<span class="sy4">;</span> <span class="co1">// OK</span>
|
|
p1<span class="sy2">-</span><span class="sy1">></span>x <span class="sy1">=</span> <span class="nu0">1</span><span class="sy4">;</span> <span class="co1">// OK</span>
|
|
|
|
ST st <span class="sy1">=</span> <span class="br0">{</span><span class="br0">}</span><span class="sy4">;</span>
|
|
<span class="kw4">auto</span> p2 <span class="sy1">=</span> <span class="kw1">reinterpret_cast</span><span class="sy1"><</span>S<span class="sy2">*</span><span class="sy1">></span><span class="br0">(</span><span class="sy3">&</span>st<span class="br0">)</span><span class="sy4">;</span> <span class="co1">// p2 的值为“指向 st 的指针”</span>
|
|
<span class="kw4">auto</span> i <span class="sy1">=</span> p2<span class="sy2">-</span><span class="sy1">></span>x<span class="sy4">;</span> <span class="co1">// 未定义行为</span>
|
|
p2<span class="sy2">-</span><span class="sy1">></span>x <span class="sy1">=</span> <span class="nu0">1</span><span class="sy4">;</span> <span class="co1">// 未定义行为</span></pre></div>
|
|
</div>
|
|
<p>许多编译器在这种情况下发布“严格别名化”警告,即使在技术上这种构造所违背的并非称为“严格别名化规则”段落的规则。</p>
|
|
<p>严格别名化及其相关规则的目的,是启用基于类型的别名分析,若程序能合法地创建一种情形,使得两个指向无关类型的指针(例如一个 <span class="t-c"><span class="mw-geshi cpp source-cpp"><span class="kw4">int</span><span class="sy2">*</span></span></span> 和一个 <span class="t-c"><span class="mw-geshi cpp source-cpp"><span class="kw4">float</span><span class="sy2">*</span></span></span>)能同时存在并可一同用于加载或存储同一内存(见<a rel="nofollow" class="external text" href="http://www.open-std.org/pipermail/ub/2016-February/000565.html">此 SG12 reflector 上的邮件</a>),则别名分析会普遍无效。故任何看起来能够创建这种情形的技巧都必然导致未定义行为。</p>
|
|
<p>当需要将对象的字节解释为不同类型的值时,可以使用 <span class="t-lc"><a href="cpp-string-byte-memcpy.html">std::memcpy</a></span> <span class="t-rev-inl t-since-cxx20"><span>或 <a href="cpp-numeric-bit_cast.html"><tt>std::bit_cast</tt></a></span> <span><span class="t-mark-rev t-since-cxx20">(C++20 起)</span></span></span>:</p>
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="cpp source-cpp">
|
|
<pre class="de1"><span class="kw4">double</span> d <span class="sy1">=</span> <span class="nu16">0.1</span><span class="sy4">;</span>
|
|
<a href="cpp-types-integer.html"><span class="kw109">std::<span class="me2">int64_t</span></span></a> n<span class="sy4">;</span>
|
|
static_assert<span class="br0">(</span>sizeof n <span class="sy1">==</span> sizeof d<span class="br0">)</span><span class="sy4">;</span>
|
|
<span class="co1">// n = *reinterpret_cast<std::int64_t*>(&d); // 未定义行为</span>
|
|
<a href="cpp-string-byte-memcpy.html"><span class="kw1159">std::<span class="me2">memcpy</span></span></a><span class="br0">(</span><span class="sy3">&</span>n, <span class="sy3">&</span>d, sizeof d<span class="br0">)</span><span class="sy4">;</span> <span class="co1">// OK</span>
|
|
n <span class="sy1">=</span> std<span class="sy4">::</span><span class="me2">bit_cast</span><span class="sy1"><</span><a href="cpp-types-integer.html"><span class="kw109">std::<span class="me2">int64_t</span></span></a><span class="sy1">></span><span class="br0">(</span>d<span class="br0">)</span><span class="sy4">;</span> <span class="co1">// 亦 OK</span></pre></div>
|
|
</div>
|
|
<table class="t-rev-begin">
|
|
<tr class="t-rev t-since-cxx11">
|
|
<td>
|
|
<p>若实现提供 <span class="t-lc"><a href="cpp-types-integer.html">std::intptr_t</a></span> 与/或 <span class="t-lc"><a href="cpp-types-integer.html">std::uintptr_t</a></span>,则从指向对象类型或 <i>cv</i> <span class="t-c"><span class="mw-geshi cpp source-cpp"><span class="kw4">void</span></span></span> 的指针到这些类型的转型始终为良定义。然而这对于函数指针并不保证。</p>
|
|
</td>
|
|
<td><span class="t-mark-rev t-since-cxx11">(C++11 起)</span></td>
|
|
</tr>
|
|
</table>
|
|
<h3><span class="mw-headline" id=".E7.BC.BA.E9.99.B7.E6.8A.A5.E5.91.8A">缺陷报告</span></h3>
|
|
<p>下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。</p>
|
|
<table class="dsctable" style="font-size:0.8em">
|
|
<tr>
|
|
<th>DR</th>
|
|
<th>应用于</th>
|
|
<th>出版时的行为</th>
|
|
<th>正确行为</th>
|
|
</tr>
|
|
<tr>
|
|
<td><a rel="nofollow" class="external text" href="https://wg21.cmeerw.net/cwg/issue195">CWG 195</a></td>
|
|
<td>C++98</td>
|
|
<td>不允许函数指针和对象指针间的转换</td>
|
|
<td>改为条件性支持</td>
|
|
</tr>
|
|
</table>
|
|
<h3><span class="mw-headline" id=".E7.A4.BA.E4.BE.8B">示例</span></h3>
|
|
<div class="t-example">
|
|
<p>演示 reinterpret_cast 的一些用法:</p>
|
|
<div class="t-example-live-link"></div>
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="cpp source-cpp">
|
|
<pre class="de1"><span class="co2">#include <cstdint></span>
|
|
<span class="co2">#include <cassert></span>
|
|
<span class="co2">#include <iostream></span>
|
|
<span class="kw4">int</span> f<span class="br0">(</span><span class="br0">)</span> <span class="br0">{</span> <span class="kw1">return</span> <span class="nu0">42</span><span class="sy4">;</span> <span class="br0">}</span>
|
|
<span class="kw4">int</span> main<span class="br0">(</span><span class="br0">)</span>
|
|
<span class="br0">{</span>
|
|
<span class="kw4">int</span> i <span class="sy1">=</span> <span class="nu0">7</span><span class="sy4">;</span>
|
|
|
|
<span class="co1">// 指针到整数并转回</span>
|
|
<a href="cpp-types-integer.html"><span class="kw133">std::<span class="me2">uintptr_t</span></span></a> v1 <span class="sy1">=</span> <span class="kw1">reinterpret_cast</span><span class="sy1"><</span><a href="cpp-types-integer.html"><span class="kw133">std::<span class="me2">uintptr_t</span></span></a><span class="sy1">></span><span class="br0">(</span><span class="sy3">&</span>i<span class="br0">)</span><span class="sy4">;</span> <span class="co1">// 不能误用 static_cast</span>
|
|
<a href="cpp-io-cout.html"><span class="kw1758">std::<span class="me2">cout</span></span></a> <span class="sy1"><<</span> <span class="st0">"&i 的值是 0x"</span> <span class="sy1"><<</span> <a href="cpp-io-manip-hex.html"><span class="kw1782">std::<span class="me2">hex</span></span></a> <span class="sy1"><<</span> v1 <span class="sy1"><<</span> <span class="st0">'<span class="es1">\n</span>'</span><span class="sy4">;</span>
|
|
<span class="kw4">int</span><span class="sy2">*</span> p1 <span class="sy1">=</span> <span class="kw1">reinterpret_cast</span><span class="sy1"><</span><span class="kw4">int</span><span class="sy2">*</span><span class="sy1">></span><span class="br0">(</span>v1<span class="br0">)</span><span class="sy4">;</span>
|
|
<a href="cpp-error-assert.html"><span class="kw774">assert</span></a><span class="br0">(</span>p1 <span class="sy1">==</span> <span class="sy3">&</span>i<span class="br0">)</span><span class="sy4">;</span>
|
|
|
|
<span class="co1">// 到另一函数指针并转回</span>
|
|
<span class="kw4">void</span><span class="br0">(</span><span class="sy2">*</span>fp1<span class="br0">)</span><span class="br0">(</span><span class="br0">)</span> <span class="sy1">=</span> <span class="kw1">reinterpret_cast</span><span class="sy1"><</span><span class="kw4">void</span><span class="br0">(</span><span class="sy2">*</span><span class="br0">)</span><span class="br0">(</span><span class="br0">)</span><span class="sy1">></span><span class="br0">(</span>f<span class="br0">)</span><span class="sy4">;</span>
|
|
<span class="co1">// fp1(); 未定义行为</span>
|
|
<span class="kw4">int</span><span class="br0">(</span><span class="sy2">*</span>fp2<span class="br0">)</span><span class="br0">(</span><span class="br0">)</span> <span class="sy1">=</span> <span class="kw1">reinterpret_cast</span><span class="sy1"><</span><span class="kw4">int</span><span class="br0">(</span><span class="sy2">*</span><span class="br0">)</span><span class="br0">(</span><span class="br0">)</span><span class="sy1">></span><span class="br0">(</span>fp1<span class="br0">)</span><span class="sy4">;</span>
|
|
<a href="cpp-io-cout.html"><span class="kw1758">std::<span class="me2">cout</span></span></a> <span class="sy1"><<</span> <a href="cpp-io-manip-hex.html"><span class="kw1781">std::<span class="me2">dec</span></span></a> <span class="sy1"><<</span> fp2<span class="br0">(</span><span class="br0">)</span> <span class="sy1"><<</span> <span class="st0">'<span class="es1">\n</span>'</span><span class="sy4">;</span> <span class="co1">// 安全</span>
|
|
|
|
<span class="co1">// 通过指针的类型别名化</span>
|
|
<span class="kw4">char</span><span class="sy2">*</span> p2 <span class="sy1">=</span> <span class="kw1">reinterpret_cast</span><span class="sy1"><</span><span class="kw4">char</span><span class="sy2">*</span><span class="sy1">></span><span class="br0">(</span><span class="sy3">&</span>i<span class="br0">)</span><span class="sy4">;</span>
|
|
<span class="kw1">if</span><span class="br0">(</span>p2<span class="br0">[</span><span class="nu0">0</span><span class="br0">]</span> <span class="sy1">==</span> <span class="st0">'\x7'</span><span class="br0">)</span>
|
|
<a href="cpp-io-cout.html"><span class="kw1758">std::<span class="me2">cout</span></span></a> <span class="sy1"><<</span> <span class="st0">"本系统是小端的<span class="es1">\n</span>"</span><span class="sy4">;</span>
|
|
<span class="kw1">else</span>
|
|
<a href="cpp-io-cout.html"><span class="kw1758">std::<span class="me2">cout</span></span></a> <span class="sy1"><<</span> <span class="st0">"本系统是大端的<span class="es1">\n</span>"</span><span class="sy4">;</span>
|
|
|
|
<span class="co1">// 通过引用的类型别名化</span>
|
|
<span class="kw1">reinterpret_cast</span><span class="sy1"><</span><span class="kw4">unsigned</span> <span class="kw4">int</span><span class="sy3">&</span><span class="sy1">></span><span class="br0">(</span>i<span class="br0">)</span> <span class="sy1">=</span> <span class="nu0">42</span><span class="sy4">;</span>
|
|
<a href="cpp-io-cout.html"><span class="kw1758">std::<span class="me2">cout</span></span></a> <span class="sy1"><<</span> i <span class="sy1"><<</span> <span class="st0">'<span class="es1">\n</span>'</span><span class="sy4">;</span>
|
|
|
|
<span class="br0">[</span><span class="br0">[</span>maybe_unused<span class="br0">]</span><span class="br0">]</span> <span class="kw4">const</span> <span class="kw4">int</span> <span class="sy3">&</span>const_iref <span class="sy1">=</span> i<span class="sy4">;</span>
|
|
<span class="co1">// int &iref = reinterpret_cast<int&>(const_iref); // 编译错误——不能去除 const</span>
|
|
<span class="co1">// 必须用 const_cast 代替:int &iref = const_cast<int&>(const_iref);</span>
|
|
<span class="br0">}</span></pre></div>
|
|
</div>
|
|
<p>可能的输出:</p>
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="text source-text">
|
|
<pre class="de1">&i 的值是 0x7fff352c3580
|
|
42
|
|
本系统是小端的
|
|
42</pre></div>
|
|
</div>
|
|
</div>
|
|
<h3><span class="mw-headline" id=".E5.8F.82.E9.98.85">参阅</span></h3>
|
|
<table class="t-dsc-begin">
|
|
<tr class="t-dsc">
|
|
<td><a href="cpp-language-const_cast.html">const_cast 转换</a></td>
|
|
<td>添加或移除 const</td>
|
|
</tr>
|
|
<tr class="t-dsc">
|
|
<td><a href="cpp-language-static_cast.html">static_cast 转换</a></td>
|
|
<td>进行基本转换</td>
|
|
</tr>
|
|
<tr class="t-dsc">
|
|
<td><a href="cpp-language-dynamic_cast.html">dynamic_cast 转换</a></td>
|
|
<td>进行有检查的多态转换</td>
|
|
</tr>
|
|
<tr class="t-dsc">
|
|
<td><a href="cpp-language-explicit_cast.html">显式转型</a></td>
|
|
<td>在类型间自由转换</td>
|
|
</tr>
|
|
<tr class="t-dsc">
|
|
<td><a href="cpp-language-implicit_conversion.html">标准转换</a></td>
|
|
<td>从一个类型到另一类型的隐式转换</td>
|
|
</tr>
|
|
</table>
|
|
</div>
|
|
<div class="visualClear"></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</body>
|
|
</html>
|