【问题标题】:c++ difference between reinterpret cast and c style castc++ reinterpret cast和c style cast之间的区别
【发布时间】:2015-02-06 05:23:29
【问题描述】:

代码:

char keyStr[50]={ 0x5F, 0x80 /* bla bla */ };
uint32_t* reCast  = reinterpret_cast< uint32_t* >( &keyStr[29] );
uint32_t* reCast2 = ( uint32_t* )&keyStr[29];
if( reCast == reCast2 ){
    cout << "Same Thing!";
}

输出:

同样的事情!

我想知道这两种铸造方法有什么区别。 此外,如果您可以指定(通过示例)static_cast、dynamic_cast 和您知道的其他类型的转换(即尽可能保持低级并尽可能接近汇编语言)之间的区别。

static_cast
dynamic_cast
const_cast
reinterpret_cast
C-style cast (type)value
Function-style cast type(value)

谢谢。

请阅读 P.S. 我从上面的示例中知道 reinterpret_cast 将 keyStr[29] 的地址分配给 int 指针 在汇编中会转化为:

lea eax, [keyStr+1D]
mov [reCast], eax

所以换句话说,reinterpret_cast,在低层次的预期中,一点也不危险,因为它不会修改原始数据。

我想知道其他转换方法在低级别的表现如何。 因此,例如,一个对象,以低级方式,只是一个保存地址的变量。 如果该对象的类型是编译器如何解释该地址以及它如何偏移它。(这正是我不感兴趣的,在汇编中,如果该变量包含值、指针或对象(即另一个指针))。 另一件可能相同的事情是 int 和 int* 或 unsigned int 和 int 之间的区别;所有 4 个声明都生成相同的汇编指令。 ( push value ) or (sub esp-(length of int) && mov esp, value) 我希望这能澄清问题以及为什么我将其标记为“低级代码”和“程序集”

附:在这个程序中,我正在尝试创建我不关心不可移植性或其他高级别的东西。我正在尝试尽可能低级并尽可能接近汇编语言。这意味着,对于这个程序,内存只是内存(即 0 和 1 位)并且类型并不重要(例如,我不在乎 mem address: 0x123 是“int”类型还是“float”类型,它只是“数据”)

【问题讨论】:

  • 这个问题不同,因为它不要求高水平的东西。保持真实,并记住对象只是内存中结构化的普通数据。
  • 阅读副本后还有什么问题没有得到解答?
  • 重复的问题确实回答了我的大部分问题,但没有对幕后发生的事情提供公平的解释。我将编辑问题以添加更多详细信息。
  • 请注意,将 uint32_t* 转换为指向 char[] 数组对象是 C 和 C++ 中的严格别名未定义行为。 (除非您使用的是 MSVC,它定义了各种指针的别名行为。)

标签: c++ c assembly casting low-level-code


【解决方案1】:

reinterpret_castconst_cast 是绕过 C++ 类型系统的方法。正如您对reinterpret_cast 所指出的,这通常意味着很少或没有汇编代码。

static_cast 主要尊重 C++ 类型系统。它可以将数字从一种类型转换为另一种类型,或者调用构造函数,或者调用转换函数。或者对于派生到基础的转换,它可能涉及将字节偏移量和/或查找添加到 vtable 中。 static_cast 还可以通过将指针或引用从非虚拟基类型“向下转换”为派生类型来改变类型系统的规则,可能会减去一个字节偏移量。

还有指向成员的指针。他们可能在这里跑题了,但static_cast 对他们所做的事情或多或少类似于类指针转换。

dynamic_cast 更加严格地尊重 C++ 类型系统。在其有用的形式中,它在运行时检查指针/引用是否实际指向/引用指定类型的对象。它通常在后台调用一个魔术库函数。

带有一个参数的函数样式转换与 C 样式转换具有完全相同的效果。 (如果有多个参数,函数样式转换必须是使用类构造函数的临时初始化。)C 样式转换执行以下列表中有意义的第一件事:

  • const_cast
  • static_cast
  • static_cast 然后是const_cast
  • reinterpret_cast,或
  • reinterpret_cast 然后是const_cast

一个例外:C 风格的转换可以忽略类之间的私有和受保护继承关系,假装它们具有公共继承关系。

C 风格的转换在 C++ 中通常不是首选,因为它不太具体地说明您想要发生的事情。

【讨论】:

    【解决方案2】:

    “不危险”是什么意思? reinterpret_cast 非常危险。它告诉编译器忽略它认为知道的值是安全的。

    它不像 c 样式转换那样危险,它会丢弃所讨论值的 const/volatile 以及有关它所指向的任何信息。

    用汇编语言理解这些操作有点毫无意义。它们不是汇编语言结构。它们是 C++ 语言结构,其工作原理如下:

    static_cast - 实际上这会将对象从一种类型转换为另一种类型。请注意,这可以更改值(例如,static_cast&lt;float&gt;(1) 的位模式与 1 不同)。

    dynamic_cast - 如果这个对象可以通过继承被认为是另一种类型,则将其视为另一种类型,否则将其呈现为零。这不会改变指针的值,但会安全地改变编译器对它的看法。

    const_cast - 丢弃const(或volatile)限定符,这通常不是一个好主意,因为它允许您破坏客户认为安全的数据。

    reinterpret_cast - 将位模式视为与编译器认为的不同的含义。通常用于指针,希望很少。 reinterpret_cast将 int 转换为 float 不太可能是一个好主意,但它会保持相同的位模式。

    c-style-cast - 采用位模式,完全忘记你对它的了解,并将其视为其他东西。 static_castreinterpret_castconst_cast 的危险且几乎看不见的组合。这在 C++ 代码中不被认为是一个好主意,因为在评论中很难发现它,并且因为它没有具体说明正在发生的事情。

    【讨论】:

    • 考虑一个程序,它要求您提供一个给定用户名的连续剧。用户名的 reinterpret_cast 连续剧会以何种方式变得危险?它是一种算法,它可以工作,而且就一般人所知,在这个过程中有一个复杂的高级串行生成。为什么你会说重新解释演员表很危险,当然是以低水平的方式?
    • 这很危险,因为如果你 reinterpret_cast 对需要 32 位对齐的东西说 char *,你会得到随机和讨厌的对齐错误。编译器无法检查你正在做的事情是否安全
    • 这个算法的特别之处在于它在高级语言中没有意义,这意味着编译器对某个地址的某些数据的类型的解释阻碍了算法本身的实现,这就是我使用 reinterpret_cast 的原因,因此我可以将 4 个字符的数组作为 uint32_t 或 uint32_t 作为 int32_t 工作(并处理)。但无论如何,你能提供一个对齐错误的例子吗?
    • char c; char a[4]; ;wibble(&amp;a[0]); /*...*/ void wibble(void *a) { int b = *reinterpret_cast&lt;int *&gt;(a);} 会编译并可能会严重崩溃(在需要对齐的架构上)。还有证据表明,我们的其中一个处于调试模式的编译器会将事物对齐到它可以找到的最坏的边界上,并且您不需要在其中声明 c
    • 我不明白你提供的代码有什么问题,假设它有问题。它只是创建一个 4 字节数组(即 char a[4]),然后调用一个函数,该函数创建另一个 4 字节数组(即 int b),然后将 a 的 4 个字节存储在 b 中。该代码确实在我的机器上成功编译,没有任何错误;它也成功运行而没有崩溃。
    【解决方案3】:

    在您的示例中,C 样式转换和 reinterpret_cast 之间没有区别,因为您在不相关的指针之间进行转换,并且没有 constness。如果你有一个const,当 C 风格的演员在引擎盖下完成 const_cast 时, reinterpret_cast 会窒息。

    reinterpret_cast(或 C 风格转换)的危险恰恰在于它允许在不相关的对象之间进行转换。在您的示例中,您很有可能在取消引用 reCast(或 reCast2)时收到错误,因为您尝试访问未对齐的整数。

    在低级别,所有转换都具有相同的效果(如果它们有效):它们都会给出值或地址。主要区别在于:

    • 在编译时(几乎)总是允许使用 C 样式转换 - 我不知道它会给出编译错误的示例,但它可能取决于编译器
    • 如果没有 constness 更改,则在相同情况下将允许 reinterpret_cast
    • const_cast 只能改变 constness
    • 仅允许在相关类型之间(在编译时)使用 static_cast

    所有这些转换都是在 C++ 中添加的,以避免 C 样式转换的全部模式,并允许进行一些编译和运行时检查。 - 只有在编译时相关类型之间才允许使用 dynamic_cast 并且编译器将插入代码以控制运行时的有效性

    【讨论】:

    • "低等级时,所有施法效果相同。"那是错的!考虑: { float fval = 7; int ival = (int)fval; cout
    • @Fresco 我的意思是 C 风格转换、重新解释转换或静态转换都具有相同的效果。但当然,转换数值和转换指针会做不同的事情。
    • @Fresco :我对其进行了测试,reinterpret_cast&lt;int&gt;(7.0) 给出了编译错误,但static_cast&lt;int&gt;(7.1) 给出了7(int) 7.1 一样。
    【解决方案4】:

    不同之处在于,在某些情况下,在 C++ 文件中使用 C 样式强制转换会出错并且无法编译。 reinterpret_cast 解决了这种情况。像 - 你告诉编译器:“我知道这是不兼容的转换,但假设它没问题”。在诸如强制转换之类的事情上,C++ 比 C 更受限制。

    【讨论】:

    • 不,reinterpret_cast 不会编译但 C 样式转换不会编译。
    猜你喜欢
    • 2015-10-10
    • 2014-08-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-01-31
    • 2019-06-07
    • 2020-05-18
    相关资源
    最近更新 更多