指针转换被认为是昂贵的吗? (例如,转换指针/地址需要多少CPU周期),特别是当你必须经常这样做时(例如,只是一个显示频率范围的例子,我知道这种特殊情况有更好的方法) :
unsigned long long *x;
/* fill data to x*/
for (int i = 0; i < 1000*1000*1000; i++)
{
A[i]=foo((unsigned char*)x+i);
};
答案 0 :(得分:9)
(例如,转换指针/地址所需的CPU周期数)
在大多数机器代码语言中,只有1个“类型”的指针,因此在它们之间进行转换不需要任何费用。请记住,C ++类型实际上只存在于编译时。
真正的问题是这种代码可以破坏严格的别名规则。您可以在其他地方阅读更多相关内容,但实际上编译器会通过未定义的行为生成错误的代码,或者被迫做出保守的假设,从而产生较慢的代码。 (请注意,char*
和朋友在某种程度上可以免于未定义的行为部分)
优化器通常必须在存在指针的情况下对变量做出保守的假设。例如,知道变量x的值为5的常量传播过程在分配给另一个变量(例如,* y = 10)后将无法继续使用此信息,因为它可能是* y是别名x。在y =&amp; x。
之类的作业之后可能就是这种情况作为赋值给* y的效果,x的值也会改变,因此将x为5的信息传播到* y = 10之后的语句可能是错误的(如果* y确实是x)的别名。但是,如果我们有关于指针的信息,则常量传播过程可以进行如下查询:can x是* y的别名吗?然后,如果答案为否,则可以安全地传播x = 5。 受混叠影响的另一个优化是代码重新排序。如果编译器确定x没有* y的别名,则可以在赋值* y = 10之前移动使用或更改x值的代码,如果这样可以改进调度或启用更多循环优化。< / p>
要以可预测的方式启用此类优化,C编程语言的ISO标准(包括其较新的C99版本,请参见第6.5节,第7段)指定对于不同类型的指针,它是非法的(有一些例外)引用相同的内存位置。这个规则被称为“严格别名”,有时可以令人印象深刻地提高性能,[1]但是已经知道打破一些其他有效的代码。一些软件项目故意违反C99标准的这一部分。例如,Python 2.x这样做是为了实现引用计数,[2]并且需要对Python 3中的基本对象结构进行更改以实现此优化。 Linux内核这样做是因为严格的别名会导致优化内联代码的问题。[3]在这种情况下,使用gcc编译时,会调用-fno-strict-aliasing选项以防止可能产生意外代码的不需要的优化。 [编辑]
http://en.wikipedia.org/wiki/Aliasing_(computing)#Conflicts_with_optimization
答案 1 :(得分:6)
在您可能遇到的任何体系结构上,所有指针类型都具有相同的表示形式,因此表示相同地址的不同指针类型之间的转换没有运行时成本。这适用于C中的所有指针转换。
在C ++中,一些指针转换有成本,有些则没有:
reinterpret_cast
和const_cast
(或等效的C风格演员,例如问题中的那个)和转换到void*
或从static_cast
转换将只重新解释指针值,没有成本。 dynamic_cast
或等效的C风格转换)可能需要在指针值处添加固定偏移量是多个基类。历史上,某些体系结构(例如PDP-10)对指针到字节和指针到字的表示方式不同;转换可能会有一些运行时成本。
答案 2 :(得分:1)
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
}
请记住,机器只知道内存地址,数据和代码。其他所有东西(比如类型等)只有编译器知道(帮助程序员),并且所有指针算术都是已知的,只有编译器知道每种类型的大小......依此类推。
在运行时,在将一种指针类型转换为另一种指针类型时不会浪费任何机器周期,因为转换不会在运行时发生。所有指针都被视为4个字节长(在32位机器上),仅此而已。
答案 3 :(得分:0)
这完全取决于您的底层硬件。
在大多数机器架构上,所有指针都是字节指针,并且字节指针和字节指针之间的转换是无操作。在某些体系结构上,指针转换在某些情况下可能需要额外的操作(例如,有些机器使用基于字的地址,将字指针转换为字节指针,反之亦然需要额外的操作)。
此外,这通常是一种不安全的技术,因为编译器无法对您正在执行的操作执行任何健全性检查,并且您最终可能会覆盖您不期望的数据。