以下几行:
typedef struct foo {.....} foo_t;
foo_t array[1000];
foo_t* ptr = &array[50];
最后一行是否等同于
foo_t* ptr = array + 50
因为假设foo_t
很大,将array[50]
转换为foo_t
的实例,然后获取地址会很昂贵。
答案 0 :(得分:0)
假设编译器合理,编译器应生成等效的:
ptr = (char*)array + 50 * sizeof(foo_t);
对于这两种情况,是的。 (转化为char*
只是为了表示需要将sizeof(foo_t)
乘以声明。
无论如何,实际上没有其他方法可以找到&array[50]
的值。
请注意50 * sizeof(foo_t)
的关键点是,在添加到array
的基址之前,我们需要MULTIPLY索引来生成字节地址值。对于典型情况,array
的地址是常量且偏移量是常数[sizeof(foo_t)
本质上是常量,或者你不能声明变量的数组],编译器的意思是当然,优化整个array + 50 * sizeof(foo_t)
使得它只是代码中的常量(一旦它被链接并重新定位到数据地址)。
如果50
被x
替换,这是一个仅在运行时知道的值,那么在add之前会有一个乘法[如果被乘数足够简单,则可以将乘法优化为更快的操作,例如x * 9
= x * 8 + x
作为一条指令,因为有支持乘以1,2,4,8和16 - 至少在某些处理器,甚至是RISC处理器中,乘法通常比a很少添加和移位操作 - 小数字通常很容易处理这种方式,但575或13412可能不那么容易转换为少量的简单操作,因此需要适当的乘法。
但不管怎样,&array[50]
和array + 50
的地址计算都是相同的 - 99%肯定会在编译时计算出来。如果在编译时未知,则对array + x
,x + array
,&array[x]
和&x[array]
执行相同的计算 - 因为array[x]
和*(array + x)
(并且使用地址运算符将只删除对元素1的实际访问权限)与语言定义相同,并且这种转换很早就在编译阶段发生,因此它们在后面变得无法区分 - 实际执行代码生成的结束。
1在我的Pascal编译器中,我有一个函数用于执行Address
的抽象语法树类,并且对变量值的访问是value = Load(AST.Address())
或Store(value, AST.Address())
作为通用解决方案。参见: