interpret_cast

C++ reinterpret_cast

  来源
  翻译

  通过重新解释潜在的比特模型(但没有进行相应的二进制转换)实现类型之间的转换。

如:


#include <iostream>



using namespace std;



int main(void)

{

    int t = 3;

    double d = reinterpret_cast<double&>(t);

    cout << "t = " << t << endl 

        << "d = " << d << endl;

    return 0;

}



----



可能的结果:

t = 3

d = 6.95285e-308

语法

  reinterpret_cast (expression);

  返回new_type类型的值。

解释

  与static_cast不同,但和const_cast相似,reinterpret_cast表达式不会编译为任何CPU指令。它纯粹是一个编译器指令,指示编译器将表达式的比特(对象表示)序列对待为new_type类型。

  仅有以下转换可以通过reinterpret_cast完成,其中一些转换可能会丢失const与volatile。

  1. 整型、枚举、指针、指针,或成员指针类型的表达式可以转换为自身的类型。值的结果与表达式的值相同。

  2. 任意指针类型可以转换为整型类型,整型类型应该足够大以足以保存指针的值。例:·std::uintptr_t

  3. 任意整型或枚举类型的值可以转换为指针类型。指针和整型应保证以足够的大小相互转换,否则可能会导致指针不能被安全的解引用。null指针常量NULL或者整数0并不能保证转换指定类型的null指针值,可以通过static_cast与隐式转换实现这一目的。

  4. 任意std::nullptr_t类型的值,包括nullptr可以转化为任意的整型类型,仿佛它们的是(void*)0一样。但是没有值的话,即使是nullptr也不能转换为std::nullptr_t,可以通过使用static_cast达到这一目的。

  5. 任意指向类类型T1对象的指针可以转换为指向另一个类类型cv T2的指针,等价于static_cast<cv T2*>(static_cast<cv void*>(expression)),意味着如果T2的对齐要求没有T1严格,指针的值也不会发生改变,当将转换后的指针再转换为初始的类型会得到初始的值。总之,转换的指针仅当如满足类型别名规则时(如下条目说明),才可以被安全的解引用。

  6. 一个类型为T1的左值表达式可以转换为另一个类型为T2的引用。结果是一个指向初始左值对象的lvaluexvalue,但是类型不同。没有临时对象创建,没有发生复制,也没有调用构造器或转换函数。转换的引用仅当满足类型别名规则时(如下条目说明),才可以被安全的访问。

  7. 任意指向函数的指针可以转换为指向不同函数类型的指针。调用这个指向不同函数类型的指针是未定义的,但是再将这个指针转换回原来的函数指针,会得到指向原始函数类型的指针。

  8. 在一些实现上(特别地,在任何与POSIX兼容并需要dlsym的系统上),函数指针能够转换为void*,或任意其它对象的指针,反之亦然。如果系统实现支持两个方向的转换,那么将转换后的指针转换回原来的指针,便会得到初始的值。否则,转换的转换的指针不能被安全的解引用。

  9. 任意类型的空指针值可以转换为任意其它类型的指针,转换结果为目标类型的空指针值。注意,空指针常量nullptr或任意其它std::nullptr_t类型的值不能通过reinterpret_cast转换为指针。如果需要此种转换,可以通过隐式转换或static_cast来实现。

  10. 一个指向成员函数的右值指针可以指向不同类型不同成员函数的指针。当转换回初始类型可以得到原来的值,否则转换得到的指针不能被安全使用。

  11. 一个指向类类型T1成员对象的右值指针可以转换为另一个类类型T2成员对象的右值指针。如果T2的对齐要求没有T1严格,并且转换到初始类型可以得到原来的值,否则转换得到的指针不能被安全使用。

  正如其它转换表达式一样,转换结果又以下几种:

  • 如果new_type是一个左值引用类型或引用函数类型的右值引用,那么结果是左值;

  • 如果new_type是一个引用对象类型的右值引用,那么结果是xvalue;

  • 其它情况是纯右值(prvalue);

关键字

  reinterpret_cast

类型别名

  当指针或引用是一个动态类型的指针或引用时,通过reinterpret_cast转换该动态类型的别名类型时,转换始终是可以成功的。但是仅当动态类型(DynamicType)与别名类型(AliasedType)是标准布局类型(Standard-Layout Type),或者满足一下条件之一的,才可使用转换后的指针或引用访问对象。

  • 别名类型是动态类型,也可能加了cv限定符(const or volatile);

  • 别名类型与动态类型(可能是多层,也可能每一层加了cv限定符)都是指向同一类型T的指针(从C++11开始支持);

  • 别名类型是动态类型的有符号或无符号变量(可能加了cv限定符);

  • 别名类型是一个聚合类型(aggregate type)或联合类型(union type)时,其中聚合类型与联合类型的成员的类型是上诉提到的几种类型,或者是非静态成员。这时可以转换获得给定结构体指针或联合指针的安全可用的指针,指向它的非静态成员或元素;

  • 别名类型是动态类型的基类(可能加了cv限定符);

  • 别名类型是char或unsigned char:这允许将任意对象的对象表示作为一个unsigned char数组来检查;

  如果别名类型不满足这些要求,访问转换后的新指针或引用会发生未定义行为。这被称为严格别名规则(strict aliasing rules),并在C++与C语言都有应用。需要注意的是,一些C++编译器对语言标准作了非标准扩展,因此可能并不严格遵守这一规则,允许以错误的类型访问union中非活动的成员(该特性在C语言中是未定义的)。另外需要注意的是,这一规则集比C语言相应的别名规则要严格的多。C允许访问兼容类型的指针,而C++没有兼容类型,并且如果不满足以上规则,则不允许访问布局兼容的类型的指针或引用。

注意事项

  C++不允许函数指针与void *之间的转换。

例子


#include <cstdint>

#include <cassert>

#include <iostream>

int f() { return 42; }

int main()

{

    int i = 7;



    // pointer to integer and back

    uintptr_t v1 = reinterpret_cast<uintptr_t>(&i); // static_cast is an error

    std::cout << "The value of &i is 0x" << std::hex << v1 << '\n';

    int* p1 = reinterpret_cast<int*>(v1);

    assert(p1 == &i);



    // pointer to function to another and back

    void(*fp1)() = reinterpret_cast<void(*)()>(f);

    // fp1(); undefined behavior

    int(*fp2)() = reinterpret_cast<int(*)()>(fp1);

    std::cout << std::dec << fp2() << '\n'; // safe



    // type aliasing through pointer

    char* p2 = reinterpret_cast<char*>(&i);

    if(p2[0] == '\x7')

        std::cout << "This system is little-endian\n";

    else

        std::cout << "This system is big-endian\n";



    // type aliasing through reference

    reinterpret_cast<unsigned int&>(i) = 42;

    std::cout << i << '\n';

}



-----------

可能的输出结果:

The value of &i is 0x7fff352c3580

42

This system is little-endian

42

参见

  const_cast转换 添加或移除const

  static_cast转换 实现基本的转换

  dynamic_cast转换 实现多态类型之间转换检查

  explicit转换 类型之间的显示转换

  standard转换 类型之间的隐式转换

posted @ 2015-12-10 12:17  corfox  阅读(460)  评论(0编辑  收藏  举报