C++ 指针转换是否昂贵?

C++ 指针转换是否昂贵?,c++,c,pointers,C++,C,Pointers,指针转换被认为是昂贵的吗?(例如,转换一个指针/地址需要多少CPU周期),尤其是当您必须非常频繁地进行转换时,例如(只是一个显示频率范围的示例,我知道对于这种特殊情况有更好的方法): 无符号长*x; /*将数据填充到x*/ 对于(int i=0;i

指针转换被认为是昂贵的吗?(例如,转换一个指针/地址需要多少CPU周期),尤其是当您必须非常频繁地进行转换时,例如(只是一个显示频率范围的示例,我知道对于这种特殊情况有更好的方法):

无符号长*x;
/*将数据填充到x*/
对于(int i=0;i<1000*1000*1000;i++)
{
A[i]=foo((无符号字符*)x+i);
};
(例如,转换指针/地址需要多少CPU周期)

在大多数机器代码语言中,指针只有一个“类型”,所以在它们之间转换不需要任何费用。请记住C++类型只在编译时存在。

真正的问题是,这种代码可能会破坏严格的别名规则。您可以在其他地方阅读更多关于这方面的内容,但本质上,编译器要么通过未定义的行为生成错误的代码,要么被迫做出保守的假设,从而生成较慢的代码。(注意,
char*
和friends在某种程度上不受未定义行为部分的约束)

优化器通常必须在存在指针的情况下对变量做出保守的假设。例如,知道变量x的值为5的常数传播过程在分配给另一个变量(例如,*y=10)后将无法继续使用此信息,因为可能是*y是x的别名。在像y=&x这样的赋值之后可能会出现这种情况

作为对*y赋值的结果,x的值也会改变,因此将x为5的信息传播到*y=10之后的语句可能是错误的(如果*y确实是x的别名)。但是,如果我们有关于指针的信息,常数传播过程可能会产生如下查询:x可以是*y的别名吗?然后,如果答案是“否”,则可以安全地传播x=5。 另一个受别名影响的优化是代码重新排序。如果编译器确定x的别名不是*y,那么使用或更改x值的代码可以在赋值*y=10之前移动,前提是这样可以改进调度或执行更多循环优化

为了以可预测的方式实现此类优化,C编程语言的ISO标准(包括其较新的C99版本,请参见第6.5节第7段)规定,不同类型的指针引用同一内存位置是非法的(有些例外)。这条被称为“严格别名”的规则有时允许显著提高性能[1],但已知会破坏一些其他方面有效的代码。一些软件项目故意违反C99标准的这一部分。例如,Python2.x这样做是为了实现引用计数[2],并且需要对Python3中的基本对象结构进行更改以实现这种优化。Linux内核之所以这样做,是因为严格别名会导致内联代码优化出现问题。[3]在这种情况下,使用gcc编译时,会调用-fno strict aliasing选项,以防止可能产生意外代码的不必要优化。 [编辑]

无符号长*x;
/*将数据填充到x*/
对于(int i=0;i<1000*1000*1000;i++)
{
A[i]=foo((无符号字符*)x+i);//类型转换错误
}
记住,机器只知道内存地址、数据和代码。其他一切(如类型等)只有编译器知道(帮助程序员),而所有指针运算都是由编译器完成的,只有编译器知道每种类型的大小。。诸如此类


在运行时,将一种指针类型转换为另一种指针类型不会浪费任何机器周期,因为转换不会在运行时发生。所有指针都被视为4字节长(在32位机器上),不多也不少

这一切都取决于您的底层硬件

在大多数机器体系结构上,所有指针都是字节指针,字节指针和字节指针之间的转换是不可操作的。在某些体系结构上,指针转换在某些情况下可能需要额外的操作(例如,有些机器使用基于字的地址,将字指针转换为字节指针或将字节指针转换为字节指针需要额外的操作)


此外,这通常是一种不安全的技术,因为编译器无法对您正在执行的操作执行任何健全性检查,并且最终可能会覆盖您没有预料到的数据。

在您可能遇到的任何体系结构上,所有指针类型都具有相同的表示形式,因此在表示同一地址没有运行时开销。这适用于C中的所有指针转换

<>在C++中,一些指针转换有成本,而有些则不:

  • reinterpret\u cast
    const\u cast
    (或等效的C样式转换,如问题中的转换)和与
    void*
    之间的转换将简单地重新解释指针值,无需任何成本
  • 如果存在多个基类,则指向基类的指针和指向派生类的指针之间的转换(隐式转换,或使用
    静态转换
    或等效的C样式转换)可能需要向指针值添加固定偏移量
  • dynamic\u cast
    将根据指向的对象的动态类型查找指针值

历史上,某些体系结构(如PDP-10)对于指向字节的指针和指向单词的指针有不同的表示形式;转换可能会有一些运行时成本。

类型只在编译时存在。也就是说,这些类型的指针转换通常不是一个好主意。此代码不会打破严格的别名规则,因为
unsigned char*
是一个特定的例外但是,IIRC,
char
类型可以安全地别名任何其他类型。因此操作代码仍然是
unsigned long long *x;
/* fill data to x*/

for (int i = 0; i < 1000*1000*1000; i++)
{

    A[i]=foo((unsigned char*)x+i);

};
unsigned long long *x;
/* fill data to x*/

for (int i = 0; i < 1000*1000*1000; i++)
{

    A[i]=foo((unsigned char*)x+i); // bad cast

}