Pointers on C——8 Arrays.6

来源:互联网 发布:35是不是质数的算法 编辑:程序博客网 时间:2024/06/05 04:22

Switching to Pointers

#define SIZE 50

int x[SIZE];

int y[SIZE];

int I;

int *p1, *p2;

Now letʹs rewrite the function with pointers.

void

try2()

{

for( p1 = x, p2 = y; p1 – x < SIZE; )

*p1++ = *p2++;

}

Iʹve replaced the subscripts with pointer variables. One of the pointers is tested to determine when to exit the loop, so the counter is no longer needed.

我用指针变量取代了下标。其中一个指针用于测试,判断何时退出循环,所以这个方案不再需要计数器。



These changes do not give much of an improvement over the first version. The code needed to copy an integer and increment the pointers has decreased, but the initialization code has increased. The shifts to scale the subscript are gone, and the movl instruction that does the real work no longer uses indexing. But the code to check for the end of the loop has increased a lot, because the subtraction of two pointers must be scaled (in this case, divided by 4). The division is performed by pushing the values on the stack and calling a subroutine named ldiv. If this machine had a 32‐bit divide instruction, the division might have been done more efficiently.

和第1 个版本相比,这些变化并没有带来多大的改进。需要复制整数并增加指针值的代码减少了,但初始化代码却增加了。用于代替乘法的移位指令不见了,而且执行真正任务的movl 指令不再使用索引。但是,用于检查循环结束的代码却增加了许多,因为两个指令相减的结果必须进行调整(在这里是除以4)。除法运算是通过把值压到堆栈上并调用子程序ldiv 实现的。如果这台机器具有32 位除法指令,除法运算可能会完成得更有效率。


Bringing Back the Counter

Letʹs try another approach

void

try3()

{

for( i = 0, p1 = x, p2 = y; i < SIZE; i++ )

*p1++ = *p2++;

}

Iʹve used the counter again to control when the loop should exit to get rid of the pointer subtraction and the resulting long sequence of code.

我重新使用了计数器,用于控制循环何时退出,这样可以去除指针减法,并因此缩短目标代码的长度。



This version has the shorter code to copy the integer and increment the pointers, and to control when the loop breaks. But weʹre still copying the pointer variables into address registers before the indirection.

在这个版本中,用于复制整数和增加指针值以及控制循环结束的代码要短一些。但在执行间接访问之前,我们仍需把指针变量复制到地址寄存器。


Register Pointer Variables

We can eliminate copying the pointer values by using register variables for the pointers. However, they must be declared as local variables.

我们可以对指针使用寄存器变量,这样就不必复制指针值。但是,它们必须被声明为局部变量。

void

try4()

{

register int *p1, *p2;

register int i;

for( i = 0, p1 = x, p2 = y; i < SIZE; i++ )

*p1++ = *p2++;

}

This change improves more than just eliminating the copying of the pointers.

这个变化带来了较多的改进,并不仅仅是消除了复制指针的过程。


Note that the pointer variable exist in registers a4 and a5 from the start. We can increment them directly with the hardwareʹs autoincrement addressing mode (which behaves very much like the C postfix ++ operator). The initialization and loop termination code is, for the most part, unchanged. This code is looking better.

注意,指针变量一开始就保存于寄存器a4 和a5 中,我们可以使用硬件的地址自动增量模型(这个行为非常像C 的后缀++操作符)直接增加它们的值。初始化和用于终止循环的代码基本未作变动。这个版本的代码看上去更好一些。


Eliminating the Counter

If we can find a way to terminate the loop without using the pointer subtraction that caused trouble earlier, we can eliminate the counter.

如果我们能找到一种方法来判断循环是否终止,但并不使用开始所提到的那种会引起麻烦的指针减法,我们就可以消除计数器。


void

try5()

{

register int *p1, *p2;

for( p1 = x, p2 = y, p1 < &x[SIZE]; )

*p1++ = *p2++;

}


Instead of the subtraction to see now many elements weʹve copied, this loop checks to see whether the pointer p1 has reached the end of the source array. Functionally this test is just as good, but it should be more efficient because it does not do a subtraction.Furthermore, the expression &x[SIZE] can be evaluated at compile time, because SIZE is a literal constant. Here is the result.

这个循环并没有使用指针减法来判断已经复制了多少个元素,而是进行测试,看看pl 是否到达源数组的末尾。从功能上说,这个测试应该和前面的一样,但它的效率应该更高,因为它不必执行减法运算。而且,表达式&x[SIZE] 可以在编译时求值,因为SIZE 是个数字常量。下面是它的结果:


This code is compact and fast and rivals what an assembly language programmer would have produced. The counter and its associated instructions are gone. The comparison instruction contains the expression _x+200, which is the expression &x[SIZE]. This computation was done at compile time because SIZE is a constant. This code is about as tight as we can get on this machine.

这个版本的代码非常紧凑,速度也很快,完全可以与汇编程序员所编写的同类程序相媲美。计数器以及相关的指令不见了。比较指令包含了表达式_x+200 ,也就是源代码中的&x[SIZE] 。由于SIZE是个常量,所以这个计算可以在编译时完成。这个版本的代码是我们在这个机器上所能获得的最紧凑的代码。


上一章 Pointers on C——8 Arrays.5

原创粉丝点击