重新解释强制转换和c样式强制转换之间的c ++差异

时间:2014-12-08 14:17:43

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

代码:

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为int指针分配了keyStr的地址[29] 在汇编中将转化为:

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

所以换句话说,reinterpret_cast,在低级别的预期中,并不危险,因为它不会修改原始数据。

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

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

4 个答案:

答案 0 :(得分:4)

reinterpret_castconst_cast是绕过C ++类型系统的方法。正如您在reinterpret_cast中所提到的,这通常会转换为很少或根本没有汇编代码。

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

然后有指向成员的指针。他们可能不在这里,但static_cast或多或少类似于类指针转换。

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

具有一个参数的函数式转换与C样式转换具有完全相同的效果。 (对于多个参数,函数样式调用必须是类构造函数调用。)C样式转换首先执行以下列表中的有意义:

  • a const_cast
  • a static_cast
  • 一个static_cast,然后一个const_cast
  • a reinterpret_cast
  • 一个reinterpret_cast,然后一个const_cast

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

C风格的演员表在C ++中通常不是首选,因为它对你想要发生的事情不太具体。

答案 1 :(得分:0)

你的意思是什么?#34;不危险&#34;? reinterpret_cast非常危险。它告诉编译器忽略它认为对值的了解是安全的。

它不像c风格的演员表那样危险,它会抛弃有关价值的常数/波动性以及有关它指向的信息。

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

static_cast - 实际上,这会将对象从一种类型转换为另一种类型。请注意,这可以更改值(static_cast<float>(1)不具有与1相同的位模式。)

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

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

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

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

答案 2 :(得分:0)

在您的示例中,C样式转换和reinterpret_cast之间没有区别,因为您在不相关的指针之间进行投射,并且没有 constness 。如果你在一个部分上有一个const,那么当C样式转换在引擎盖下完成const_cast时,reinterpret_cast会被阻塞。

reinterpret_cast(或C样式转换)的危险正是它允许在不相关的对象之间进行转换。在您的示例中,当您取消引用reCast(或reCast2)时,您会遇到错误,因为您尝试访问未对齐的整数。

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

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

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

答案 3 :(得分:-1)

不同之处在于,在某些情况下使用C ++文件中的C样式转换会出现错误而无法编译。 reinterpret_cast解决了这种情况。有点像 - 你告诉编译器:“我知道它是不兼容的转换,但让我们假设它没问题”。对于像cast这样的东西,C ++比C更受限制。