5

代码:

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)

谢谢。

请阅读我从上面的示例中知道的 PS,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) 我希望这可以澄清问题以及为什么我将其标记为“低级代码”和“程序集”

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

4

4 回答 4

7

reinterpret_cast并且const_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++ 中通常不是首选,因为它不太具体地说明您想要发生的事情。

于 2014-12-08T15:25:40.307 回答
0

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

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

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

static_cast- 这有效地将对象从一种类型转换为另一种类型。请注意,这可以更改值(static_cast<float>(1)例如,与 1 的位模式不同)。

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

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

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

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

于 2014-12-08T15:29:30.573 回答
0

在您的示例中,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,编译将插入代码以控制运行时的有效性

于 2014-12-08T15:39:21.663 回答
-1

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

于 2014-12-08T15:19:49.937 回答