天道酬勤,学无止境

reinterpret_cast (p) 或 static_cast ((void*)p)) 用于字节指针差异,哪个更好?(reinterpret_cast<char*>(p) or static_cast<char*>((void*)p)) for bytewise pointer difference, which is better?)

问题

以下三种用于提取原始字节指针以用于指针运算的转换之间有什么区别吗? (假设 char 为 1 个字节的平台。)

  1. static_cast<char*>((void*)ptr))
  2. reinterpret_cast<char*>(ptr)
  3. (更新)或: static_cast<char*>(static_cast<void*>(ptr))

我应该更喜欢哪个?

更详细...

给定一个类中两个成员对象的指针,我想计算一个到另一个的偏移量,这样我就可以重建一个给定偏移量的成员的地址和另一个成员的地址。

// assumed data layout:
struct C {
  // ...
  A a;
  // ...
  B b;
}

我目前使用的代码大致如下:

void approach1( A *pa, B *pb )
{
  // compute offset:
  std::ptrdiff_t offset = static_cast<char*>((void*)pa) - static_cast<char*>((void*)pb);
  // then in some other function...
  // given offset and ptr to b, compute ptr to a:
  A *a = static_cast<A*>( (void*)(static_cast<char*>((void*)pb) + offset) );
}

main()
{
  C c;
  approach1(&c.a, &c.b);
}

我想知道以下是否更好(或更差):

void approach2( A *pa, B *pb )
{
  std::ptrdiff_t offset = reinterpret_cast<char*>(pa) - reinterpret_cast<char*>(pb);
  // ...
  A *a = reinterpret_cast<A*>( reinterpret_cast<char*>(pb) + offset );
}

这两种方法完全等效吗? 它们是否同样便携?

我的印象是, approach1()更具可移植性,因为“static_casting a pointer to and from void* 保留了地址”,而reinterpret_cast<>保证更少(参见链接中接受的答案)。

我想知道最干净的方法是什么。

更新:目的说明

许多人询问计算这些偏移量的目的是什么。 目的是构建实例偏移的元类表。 这由运行时反射机制用于自动 GUI 构建和持久性(偏移量未序列化,仅用于遍历结构)。 该代码已投入生产超过 15 年。 出于这个问题的目的,我只想知道计算指针偏移量的最便携的方法。 我无意对元类系统的工作方式进行重大更改。 此外,我通常也对执行此操作的最佳方法感兴趣,因为我想到了其他用途(例如,共享内存代码的差异指针)。

注意:我不能使用offsetof()因为在我的实际代码中我只有指向实例ab的指针,我不一定有包含对象c的类型或其他静态信息来使用offsetof() 。 我只能假设ab是同一个对象的成员。

回答1

这两个将导致相同的结果,因此差异主要是语义上的,并且reinterpret_cast具有您想要的操作的确切含义,再加上只需要一个转换而不是两个的事实(并且您的代码中的转换越少更好的)。

reinterpret_cast

5.2.10/7 :对象指针可以显式转换为不同类型的对象指针。 当对象指针类型的纯右值v转换为对象指针类型“指向cv T的指针”时,结果为static_cast< cv T* >(static_cast< cv void* >(v))。

因此,除非在中年平台上出现奇异的随机低级不同行为,否则您绝对应该使用:

reinterpret_cast<char*>(ptr);

一般来说。

也就是说,你为什么不在你的情况下使用 uintptr_t 呢? 它更合适,你不需要指针:

void approach3( A *pa, B *pb )
{
  std::ptrdiff_t offset = reinterpret_cast<std::uintptr_t>(pa) - reinterpret_cast<std::uintptr_t>(pb);
  // ...
  A *a = reinterpret_cast<A*>( reinterpret_cast<std::uintptr_t>(pb) + offset );
}

有关其他信息,请参阅:

http://en.cppreference.com/w/cpp/language/reinterpret_cast

回答2

我不建议计算班级成员地址之间的偏移距离。 编译器可能会注入填充数据,或者即使它正在工作,它也会以相同的方式仅用于在该特定主机上运行的特定编译器。 应用这种做法时有多种错误来源。 例如,如果您必须在多重虚拟继承中处理著名的虚拟表和内存布局怎么办? 这将完全使您的解决方案无法使用。

所以回到根源:你为什么要这样做? 也许有更好的解决方案。

编辑/更新

感谢您向我们解释原因。 这是一个非常有趣的方法,我直到现在才看到。 我今天学到了一些东西。

但是,我仍然坚持我的观点,应该有一种更简单的方法来处理这个问题。 只是作为证明的概念,我写了一个小应用程序来看看你的哪种方法有效。 对我来说,它们都不起作用。

该应用程序是您的一种稍微扩展的方法,它是:

#include <iostream>
#include <stdio.h>
#include <string>

struct A
{
    A(const std::string& pa) : a(pa) {printf("CTR: A address: %p\n", this) ;}
    std::string a;
};

struct B
{
    B(const std::string& pb) : b(pb) {printf("CTR: B address: %p\n", this) ;}
    std::string b;
};

// assumed data layout:
struct C {

    C() : a("astring"), b("bstring") {}
  // ...
  A a;
  // ...
  B b;
};

void approach1( A *pa, B *pb )
{

    printf("approach1: A address: %p B address: %p\n", pa, pb); 
    // compute offset:
    std::ptrdiff_t offset = static_cast<char*>((void*)pb) - static_cast<char*>((void*)pa);
    // then in some other function...
    // given offset and ptr to b, compute ptr to a:
    A *a = static_cast<A*>( (void*)(static_cast<char*>((void*)pb) + offset) );
    printf("approach1: a address: %p \n", a); 

    std::cout << "approach1: A->a=" << a->a << std::endl;
}


void approach2( A *pa, B *pb )
{
    printf("approach2: A address: %p B address: %p\n", pa, pb); 

    std::ptrdiff_t offset = reinterpret_cast<char*>(pb) - reinterpret_cast<char*>(pa);

    A *a = reinterpret_cast<A*>( reinterpret_cast<char*>(pb) + offset );
    printf("approach2: a address: %p \n", a); 
    std::cout << "approach2: A->a=" << a->a << std::endl;
}

main()
{
  C c;
  std::cout << c.a.a << std::endl;

  approach1(&c.a, &c.b);
  approach2(&c.a, &c.b);
}

它在我的计算机上的输出( uname -a Linux flood 3.13.0-33-generic #58-Ubuntu SMP Tue Jul 29 16:45:05 UTC 2014 x86_64 x86_64 x86_64 GNU/Linux )和我的编译器( g++ (Ubuntu 4.8.2-19ubuntu1) 4.8.2 ) 是:

CTR: A address: 0x7fff249f0900
CTR: B address: 0x7fff249f0908
astring
approach1: A address: 0x7fff249f0900 B address: 0x7fff249f0908
approach1: a address: 0x7fff249f0910 
approach1: A->a=<GARBAGE>
approach2: a address: 0x7fff249f0910 

其中<GARBAGE>正如预期的那样包含......垃圾。

请参阅:http://ideone.com/U8ahAL

受限制的 HTML

  • 允许的HTML标签:<a href hreflang> <em> <strong> <cite> <blockquote cite> <code> <ul type> <ol start type> <li> <dl> <dt> <dd> <h2 id> <h3 id> <h4 id> <h5 id> <h6 id>
  • 自动断行和分段。
  • 网页和电子邮件地址自动转换为链接。

相关推荐
  • reinterpret_cast 更改指针值的任何真实示例?(Any real example of reinterpret_cast changing a pointer value?)
    问题 根据 C++ 标准,指针T*到其他类型指针Q*的reinterpret_cast可以更改或不更改指针值,具体取决于实现。 我很感兴趣 - 是否有 C++ 实现的真实示例,其中使用reinterpret_cast将指针转换为其他指针类型会更改指针? 什么以及为什么在那里改变? 回答1 请注意,当标准声明它可以或不能做某事时,并不意味着当前的任何实现都具有该行为,只是它们可以。 我能想到的最接近的是硬件需要类型对齐的架构,以及在需要时决定纠正对齐的实现。 就像是: aligned8 var; aligned1 *p = reinterpret_cast<aligned1*>(&var); aligned1 *q = p + 1; // assuming aligned 1 size is not multiple of 8 aligned8 *a = reinterpret_cast<aligned8*>(q); // [1] 可能要求a成为有效指针,它必须寻址 8 的倍数内存位置,而具有较少对齐要求的参数q可以指向任何内存地址。 回答2 class A1 { int a1; }; class A2 { int a2; }; class B: public A1, public A2 { }; #define DBG(val) cout << #val << ": " <<
  • 何时使用reinterpret_cast?(When to use reinterpret_cast?)
    问题 我对reinterpret_cast和static_cast的适用性不感到困惑。 据我所读,一般规则是在编译时可以解释类型时使用static强制转换,因此使用static 。 这是C ++编译器内部也用于隐式强制转换的强制转换。 reinterpret_cast s适用于两种情况: 将整数类型转换为指针类型,反之亦然将一种指针类型转换为另一种。 我得到的一般想法是,这是不可移植的,应该避免。 我有点困惑的是我需要的一种用法,我从C调用C ++,C代码需要保留在C ++对象上,因此基本上它包含void* 。 应该使用哪种强制转换在void *和Class类型之间进行转换? 我看过static_cast和reinterpret_cast用法吗? 尽管从我所读的内容来看, static似乎更好,因为强制转换可以在编译时进行? 尽管它说使用reinterpret_cast从一种指针类型转换为另一种指针类型? 回答1 C ++标准保证以下各项: static_cast指向void*和来自void*的指针会保留地址。 也就是说,下面的a , b和c都指向相同的地址: int* a = new int(); void* b = static_cast<void*>(a); int* c = static_cast<int*>(b); reinterpret
  • (C++ 成长记录) —— C++强制类型转换运算符(static_cast、reinterpret_cast、const_cast和dynamic_cast)
    文章目录 C++强制类型转换运算符附录专业词汇百科参考文献 概述类型转换概念介绍异同对比static_castreinterpret_castconst_castdynamic_cast 小结 个人格言 C++强制类型转换运算符 附录 专业词汇百科 C语言C++指针强制类型转换 参考文献      声明: 本文有部分内容直接来自参考文献,侵删。 C++强制类型转换运算符(static_cast、reinterpret_cast、const_cast和dynamic_cast) 概述      我在日常的开发过程中,经常会用到一些类型转换的函数,主要是子类到父类的上行转换或者是父类到子类的下行转换等等,还有一些强制数据类型的转换,这些都是我们日常开发工作中经常遇到的一些常用的内容,那么今天就突发奇想,想要来总结一下关于C++的一些类型转换符的使用的技巧和一些案例,希望能够帮助到他人,也是对自己的知识点的一种记录和回顾。 类型转换 概念介绍      最初级的原始C样式的类型转换,是将类型名作为强制类型转换运算符的做法是C语言的老式做法,C++ 为保持兼容而予以保留。     C++ 引入了四种功能不同的强制类型转换运算符以进行强制类型转换:static_cast、reinterpret_cast、const_cast 和 dynamic_cast。     
  • 通过void *进行强制转换,而不是使用reinterpret_cast(casting via void* instead of using reinterpret_cast)
    问题 我在看书,发现reinterpret_cast不应该直接使用,而应该与static_cast一起转换为void *: T1 * p1=... void *pv=p1; T2 * p2= static_cast<T2*>(pv); 代替: T1 * p1=... T2 * p2= reinterpret_cast<T2*>(p1); 但是,我找不到解释为什么这比直接演员更好。 如果有人可以给我一个解释或指出答案,我将不胜感激。 提前致谢 ps我知道reinterpret_cast用途是什么,但我从未见过以这种方式使用 回答1 对于允许进行此类static_cast类型转换的类型(例如,如果T1是POD类型,而T2是unsigned char ),则使用static_cast的方法已由标准明确定义。 另一方面, reinterpret_cast完全是实现定义的-获得它的唯一保证是,您可以将指针类型转换为任何其他指针类型,然后再转换回原来的值;否则,您将获得原始值。 并且,您可以将指针类型转换为足够大的整数类型以容纳指针值(该值随实现而变化,并且根本不需要存在),然后将其转换回原始值。 更具体地说,我将引用该标准的相关部分,突出显示重要部分: 5.2.10 [expr.reinterpret.cast]: reinterpret_cast执行的映射是实现定义的。 [注意
  • 常规转换 vs. static_cast vs. dynamic_cast [重复](Regular cast vs. static_cast vs. dynamic_cast [duplicate])
    问题 这个问题已经在这里有了答案: 什么时候应该使用 static_cast、dynamic_cast、const_cast 和 reinterpret_cast? (9 个回答) 6年前关闭。 我已经编写 C 和 C++ 代码将近 20 年了,但是我从未真正理解这些语言的一个方面。 我显然使用过常规演员表,即 MyClass *m = (MyClass *)ptr; 各地,但似乎还有其他两种类型的演员,我不知道两者之间的区别。 以下代码行之间有什么区别? MyClass *m = (MyClass *)ptr; MyClass *m = static_cast<MyClass *>(ptr); MyClass *m = dynamic_cast<MyClass *>(ptr); 回答1 static_cast static_cast用于您基本上想要反转隐式转换的情况,但有一些限制和添加。 static_cast执行运行时检查。 如果您知道您引用了特定类型的对象,则应该使用它,因此无需检查。 例子: void func(void *data) { // Conversion from MyClass* -> void* is implicit MyClass *c = static_cast<MyClass*>(data); ... } int main() { MyClass c
  • 允许使用char *来别名T *。 也可以反过来吗?(Aliasing T* with char* is allowed. Is it also allowed the other way around?)
    问题 注意:此问题已重命名并减少,以使其更加集中和易于理解。 大多数评论是指旧文本。 根据该标准,不同类型的对象可能不会共享相同的存储位置。 因此,这是不合法的: std::array<short, 4> shorts; int* i = reinterpret_cast<int*>(shorts.data()); // Not OK 但是,该标准允许对此规则进行例外处理:可以通过指向char或unsigned char的指针来访问任何对象: int i = 0; char * c = reinterpret_cast<char*>(&i); // OK 但是,对我来说还不清楚是否也允许这样做。 例如: char * c = read_socket(...); unsigned * u = reinterpret_cast<unsigned*>(c); // huh? 回答1 由于涉及到指针转换,您的某些代码值得怀疑。 请记住,在那些情况下, reinterpret_cast<T*>(e)具有static_cast<T*>(static_cast<void*>(e))的语义,因为所涉及的类型是标准布局。 (实际上,我建议您在处理存储时始终通过cv void*使用static_cast 。) 仔细阅读该标准建议,在与T*进行指针转换或从T*进行指针转换的过程中
  • static_cast <>和C样式转换之间有什么区别?(What is the difference between static_cast<> and C style casting?)
    问题 有什么理由比C样式转换更偏爱static_cast<>吗? 它们相等吗? 有什么速度差异吗? 回答1 C ++样式转换由编译器检查。 C样式强制转换不是,并且在运行时可能会失败。 另外,可以轻松地搜索c ++样式强制转换,而实际上很难搜索c样式强制转换。 另一个很大的好处是4种不同的C ++样式强制转换更清楚地表达了程序员的意图。 在编写C ++时,我几乎总是在C风格上使用C ++。 回答2 简而言之: static_cast<>()为您提供了编译时检查功能,而C-Style static_cast<>()则没有。 static_cast<>()更具可读性,并且可以很容易地在C ++源代码中的任何位置发现,C_Style强制转换不是。 使用C ++强制转换可以更好地传达意图。 更多说明: 静态类型转换在兼容类型之间执行转换。 它类似于C样式的强制类型转换,但更具限制性。 例如,C样式强制转换将允许整数指针指向char。 char c = 10; // 1 byte int *p = (int*)&c; // 4 bytes 由于这会导致一个4字节指针(指向4字节数据类型的指针)指向已分配内存的1字节,因此写入此指针将导致运行时错误或覆盖某些相邻的内存。 *p = 5; // run-time error: stack corruption 与C样式强制转换相反
  • reinterpret_cast to void* 不适用于函数指针(reinterpret_cast to void* not working with function pointers)
    问题 我想重新解释将函数指针转换为 void* 变量。 函数指针的类型将是Class* (*)(void*) 。 下面是示例代码, class Test { int a; }; int main() { Test* *p(void **a); void *f=reinterpret_cast<void*>(p); } 上面的代码适用于 Visual Studio/x86 编译器。 但是使用 ARM 编译器,它会出现编译错误。 不知道为什么。 错误:#694:reinterpret_cast 不能抛弃 const 或其他类型限定符 我阅读了 Casting a function pointer to another type 中的解释 我很担心下面的解释。 在函数指针和常规指针之间进行转换(例如,将void (*)(void)转换为void* )。 函数指针的大小不一定与常规指针相同,因为在某些体系结构上它们可能包含额外的上下文信息。 这可能会在 x86 上正常工作,但请记住这是未定义的行为。 如何有效地从void (*)(void*) -> void*进行此类转换,以便至少在大多数编译器中编译几乎相同? 回答1 reinterpret_cast不能用于将指向函数的指针转换为void* 。 尽管静态、重新解释和 const 强制转换的组合不允许 C 强制转换可以执行一些其他操作
  • 为什么这个reinterpret_cast不能编译?(Why doesn't this reinterpret_cast compile?)
    问题 我知道reinterpret_cast很危险,我只是在做测试。 我有以下代码: int x = 0; double y = reinterpret_cast<double>(x); 当我尝试编译程序时,它给我一个错误提示 从“ float”类型到“ double”类型的无效转换 这是怎么回事? 我以为reinterpret_cast是可用于将苹果转换为潜艇的流氓演员,为什么这个简单的演员不能编译? 回答1 或许更好的方式来考虑reinterpret_cast是胭脂运算符,它可以将“苹果”的指针“转换”为潜艇的指针。 通过将y分配给强制类型转换返回的值,您实际上并没有强制转换值x ,您正在转换它。 也就是说, y并不指向x并假装它指向浮点数。 转换构造一个新的float类型的值,并从x赋值。 有几种方法可以使用C ++进行此转换,其中包括: int main() { int x = 42; float f = static_cast<float>(x); float f2 = (float)x; float f3 = float(x); float f4 = x; return 0; } 唯一的不同是最后一个(隐式转换)将在较高警告级别上生成编译器诊断。 但是它们在功能上都是相同的-在许多情况下实际上是相同的事情,就像在相同的机器代码中一样。 现在
  • 使用 C++ 样式转换从 Void* 转换为 TYPE*​​:static_cast 或 reinterpret_cast(Cast from Void* to TYPE* using C++ style cast: static_cast or reinterpret_cast)
    问题 因此,如果您从 Void* 转换为 Type* 或从 Type* 转换为 Void*,您应该使用: void func(void *p) { Params *params = static_cast<Params*>(p); } 或者 void func(void *p) { Params *params = reinterpret_cast<Params*>(p); } 对我来说 static_cast 似乎更正确,但我已经看到两者都用于相同的目的。 此外,转换的方向是否重要。 即我是否仍应将 static_cast 用于: _beginthread(func,0,static_cast<void*>(params) 我已经阅读了关于 C++ 风格转换的其他问题,但我仍然不确定这种情况的正确方法是什么(我认为它是 static_cast) 回答1 您应该使用 static_cast 以便正确操作指针以指向正确的位置。 但是,只有在首先使用静态强制转换将指针强制转换为 void* 时,才应该这样做。 否则,您应该将 reinterpret_cast 重新解释为与原始指针完全相同的类型(无基数等)。 回答2 为此在两边都使用static_cast ,并在没有其他强制转换操作时保存reinterpret_cast 。 以下 SO 主题提供了更多上下文和详细信息: C++
  • C++类型转换
    显示转换 C ++是一种强类型的语言。许多转换,特别是那些暗示对值的不同解释的转换,都需要显式转换,在C ++中称为类型转换。通用类型转换存在两种主要语法:函数形式和像c一样的形式: double x = 10.3; int y; y = int (x); // 函数形式 y = (int) x; // 像c一样的形式 这些通用类型转换的功能,可以满足基本数据类型的大多数需求。但是,这些运算符也可以应用于类和指向类的指针,这可能会产生代码,在语法上正确;但同时会导致运行时错误。例如,下面的代码编译没有错误: 例子 #include <iostream> using namespace std; class product { string name; }; class employee { string name; int age; public: employee (string emp_name, int emp_age) { name = emp_name; age= emp_age; } int get_age() { return age; } }; int main () { product d; employee * padd; padd = (employee *) &d; cout << padd->get_age(); return 0; }
  • C++ 四种类型转换操作符
    在c++中进行类型转换只需要在变量前加上变量类型,并且转换是双向的。 例如: int i = 0; double d = 1.9; int i1 = (int) d; double d1 = (double) i; 这种类型转换方式只适用于基本数据类型,对复杂的自定义类型不适用。 因此,C++中提供了四种类型转换符:static_cast、dynamic_cast、const_cast、reinterpret_cast。 1、dynamic_cast dynamic_cast用于类继承层次间的指针或引用转换。主要还是用于执行“安全的向下转型(safe downcasting)”,也即是基类对象的指针或引用转换为同一继承层次的其他指针或引用。至于“向上转型”(即派生类指针或引用类型转换为其基类类型),本身就是安全的,尽管可以使用dynamic_cast进行转换,但这是没必要的, 普通的转换已经可以达到目的,毕竟使用dynamic_cast是需要开销的。 不同于其它的强制类型转换,dynamic_cast在运行时会进行类型检查,如果绑定到引用或指针的对象不是目标类型的对象,则dynamic_cast失败: class Base(){virtual void dummy(){} }; class Derived:public Base{}; Base *b1 = new Base
  • 为什么要使用static_cast 是(x)而不是(int)x?(Why use static_cast<int>(x) instead of (int)x?)
    问题 我听说static_cast函数应该比C样式或简单的函数样式转换更可取。 这是真的? 为什么? 回答1 主要原因是经典C强制转换在我们称为static_cast<>() , reinterpret_cast<>() , const_cast<>()和dynamic_cast<>()之间没有区别。 这四件事完全不同。 static_cast<>()通常是安全的。 语言存在有效的转换,或者使之成为可能的适当的构造函数。 唯一有点冒险的是当您降级为继承的类时。 您必须通过语言外部的方式(例如对象中的标志)确保该对象实际上是您声称的对象的后代。 只要检查结果(指针)或考虑到可能的异常(参考), dynamic_cast<>()都是安全的。 另一方面, reinterpret_cast<>() (或const_cast<>() )始终很危险。 您告诉编译器:“相信我:我知道这看起来不像foo (看起来好像是不可变的),但是确实如此。” 第一个问题是,在不查看大量分散代码并知道所有规则的情况下,几乎不可能分辨出将在C样式转换中发生哪个。 让我们假设这些: class CDerivedClass : public CMyBase {...}; class CMyOtherStuff {...} ; CMyBase *pSomething; // filled somewhere 现在
  • C和C++的强制类型转换
    C++ 四种强制类型转换 一般来说,我们需要类型转换的场景可以分为如下几种: 整型和浮点型以及不同长度的数据相互转换 一般规则是:占用内存低的向占用内存高的自动转换,而反向则会有转换截断的问题 整型和指针相互转换 当我们试图根据某个成员变量的偏移位计算其在该对象内存空间位置时,就会需要将指针转换为整型进行计算。当计算出该变量的位置后(整型),就需要将其转换为指针类型。 整型和枚举类型相互转换。 这种转换往往发生在数学计算的场景下。因为枚举一般只是用于表意,而实际参与运算的还是整型数据。 指针和无类型指针相互转换 1. C风格的强制转换 ​ C风格的强制转换很简单,有显示转换和隐式转换,显示转换不管什么类型之间都是用以下方式: ​ Type a = (Type) b; //将b的类型强制转换为a的类型 但是C风格的强制转换可能带来一些隐患,让一些问题难以察觉.所以C++提供了一组可以用在不同场合的强制转换的函数。 2. C++ 四种强制转换类型函数 static_cast 用法为 static_cast < Type > (expression),该运算符把 expression 转换为 Type 类型,但没有运行时类型检查来保证转换的安全性。 应用的场合和要注意的问题: static_cast 作用和C语言风格强制转换的效果基本一样,由于没有运行时类型检查来保证转换的安全性
  • 为什么使用 static_cast (x) 而不是 (int)x?(Why use static_cast<int>(x) instead of (int)x?)
    问题 我听说static_cast函数应该比 C 风格或简单函数风格的转换更受欢迎。 这是真的? 为什么? 回答1 主要原因是经典的 C 类型转换在我们所说的static_cast<>() 、 reinterpret_cast<>() 、 const_cast<>()和dynamic_cast<>()之间没有区别。 这四件事是完全不同的。 static_cast<>()通常是安全的。 语言中有一个有效的转换,或者一个合适的构造函数使之成为可能。 唯一有点冒险的时候是当你转换到一个继承的类时; 您必须通过语言外部的方式(如对象中的标志)确保该对象实际上是您声称的后代。 只要检查结果(指针)或考虑可能的异常(参考), dynamic_cast<>()就是安全的。 另一方面, reinterpret_cast<>() (或const_cast<>() )总是危险的。 你告诉编译器:“相信我:我知道这看起来不像foo (这看起来好像不可变),但它是”。 第一个问题是,如果不查看大量分散的代码并了解所有规则,几乎不可能判断哪个会出现在 C 风格的类型转换中。 让我们假设这些: class CDerivedClass : public CMyBase {...}; class CMyOtherStuff {...} ; CMyBase *pSomething; // filled
  • 任何类型的指针都可以指向任何东西?(Any type of pointer can point to anything?)
    问题 这个说法正确吗? 任何“类型”的指针都可以指向任何其他类型吗? 因为相信,所以还是有疑惑。 为什么要为确定类型声明指针? 例如int或char ? 我能得到的一个解释是:如果一个int类型的指针指向一个char数组,那么当指针递增时,指针将从 0 位置跳到 2 位置,中间跳过 1 个位置(因为 int size=2 )。 也许是因为指针只保存值的地址,而不是值本身,即int或double 。 我错了吗? 这种说法正确吗? 回答1 指针可以互换,但不是必须的。 特别是在某些平台上,某些类型需要与某些字节边界对齐。 因此,尽管char可能位于内存中的任何位置,但int可能需要位于 4 字节边界上。 另一个重要的潜在差异是函数指针。 在许多平台上,指向函数的指针可能无法与指向数据类型的指针互换。 值得重申:这是特定于平台的。 我相信 Intel x86 架构对所有指针都一视同仁。 但是您很可能会遇到其他平台,但事实并非如此。 回答2 每个指针都是某种特定类型。 有一个特殊的通用指针类型void*可以指向任何对象类型,但是您必须先将void*转换为某些特定的指针类型,然后才能取消引用它。 (我忽略了函数指针类型。) 您可以将指针值从一种指针类型转换为另一种指针类型。 在大多数情况下,将指针从foo*转换为bar*并返回到foo*将产生原始值——但实际上并不能保证在所有情况下。
  • 什么时候应该使用static_cast,dynamic_cast,const_cast和reinterpret_cast?(When should static_cast, dynamic_cast, const_cast and reinterpret_cast be used?)
    问题 的正确用法是: static_cast dynamic_cast const_cast reinterpret_cast C样式转换(type)value 函数样式转换type(value) 如何决定在特定情况下使用哪个? 回答1 static_cast是您应该尝试使用的第一个演员表。 它的作用类似于类型之间的隐式转换(例如, int到float或指向void*指针),并且它还可以调用显式转换函数(或隐式函数)。 在许多情况下,没有必要明确声明static_cast ,但必须注意, T(something)语法与(T)something等效,应避免使用(稍后会详细介绍)。 T(something, something_else)是安全的,并且保证可以调用构造函数。 static_cast也可以通过继承层次结构进行static_cast 。 向上(朝向基类)进行强制转换时不必要,但是向下进行转换(只要不通过virtual继承进行转换)就可以使用。 但是,它不会进行检查,并且将层次结构static_cast降低为实际上不是对象类型的类型是未定义的行为。 const_cast可用于将const删除或添加到变量; 没有其他C ++强制转换能够将其删除(甚至不能reinterpret_cast )。 重要的是要注意,仅当原始变量为const ,才可以修改以前的const值;
  • C++进阶1:xxxx_cast类型转化
    1. 类型转换 c语言的转换; (1)隐式转换(从表示范围小的类型转化为范围大的类型) (2) 显示类型转化:强制类型转化; void*v = p; //1.1 隐式转换 p = (int*) v; //1.2显示类型转化; xxx_cast <类型> (表达式) 一共有以下四种形式: static_cast,const_cast, dynamic_cast, reinterpret_cast,提供安全性的检测,在代码中更加醒目; 1.1. static_cast 用于非多态类型之间的转换,不提供运行时的检查来确保转换的安全性。 主要有如下 基本数据类型转换int转换成enum基类和子类之间指针和引用的转换 上行转换,把子类的指针或引用转换成父类,这种转换是安全的(通常使用默认转换)。下行转换,把父类的指针或引用转换成子类,这种转换是不安全的,也需要程序员来保证(通常使用dynamic_cast)。 1.1.1 基本数据类型转换 int转换成char char c = 'a'; cout << c << endl; cout << (int)c << endl; cout << static_cast<int>(c)<< endl; 1.1.2 int转换成enum enum BOOL{ FALSE,TRUE }; BOOL b = static_cast<BOOL>(1==2)
  • C++四种强制类型转换
    C++相对于C语言,提供了四种强制类型转换:static_cast、const_cast、reinterpret_cast和dynamic_cast 类型转换的一般形式:cast-name<type>(expression); 下面详细说明四种变换的用法 一. static_cast 任何具有明确定义的类型转换,只要不包含底层const,都可以使用static_cast,static_cast具有如下特点: (1)static_cast不仅可以用在指针和引用上,还可以用在基础数据和对象上,用static_cast来处理的转换就需要两者具有"一定的关系". (2)static_cast跟传统转换方式几乎是一致的,所以只要将static_cast和圆括号去掉,再将尖括号改成圆括号就变成了传统的显示转换方式。例如基础类型的static_cast转换: float floatValue = 21.7; int intValue = 7; cout << floatValue / 7 << "\t\t" << static_cast<int> (floatValue) / 7 << endl; cout << intValue / 3 << "\t\t" << static_cast<double> (intValue) / 3 << endl; (3) 实际上static
  • 使用哪个演员表; static_cast 还是 reinterpret_cast?(Which cast to use; static_cast or reinterpret_cast?)
    问题 int i = 1000; void *p = &i; int *x = static_cast<int*>(p); int *y = reinterpret_cast<int*>(p); 应该使用哪个演员表将void*转换为int* ,为什么? 回答1 static_cast前提是您知道(通过程序的设计)指向的对象确实是int 。 static_cast 旨在逆转任何隐式转换。 您隐式转换为void* ,因此如果您知道您确实只是在反转较早的转换,则可以(并且应该)使用static_cast转换回来。 有了这个假设,没有任何东西被重新解释 - void是一个不完整的类型,这意味着它没有值,所以在任何时候你都不会将存储的 int 值解释为“void”或将存储的“void 值”解释为 int。 void*只是一种丑陋的说法,“我不知道类型,但我会将指针传递给知道类型的其他人”。 reinterpret_cast如果您省略了意味着您实际上可能正在使用不同于写入类型的类型读取内存的细节,请注意您的代码将具有有限的可移植性。 顺便说一句,在 C++ 中以这种方式使用void*指针的理由并不多。 C 风格的回调接口通常可以替换为模板函数(对于任何类似于标准函数qsort )或虚拟接口(对于任何类似于注册监听器的东西)。 如果您的 C++ 代码正在使用某些 C API