深入理解计算机系统笔记_程序的机器级表示_3.8数组的分配和访问

3.8数组分配和访问
C语言允许对指针进行运算,而计算出来的值会根据该指针引用的数据类型的大小进行伸缩。也就是说,如果p是一个指向类型为T的数据的指针,p的值为x,那么表达式p+i的值为xp+L·i,这里L是数据类型T的大小
数组引用A〔i]等同于表达式*(A+i)。它计算第i个数组元素的地址,然后访问这个内存位置。
在这里插入图片描述
扩展一下前面的例子,假设整型数组E的起始地址和整数索引i分别存放在寄存器各rdx和rcx中。下面是一些与E有关的表达式。我们还给出了每个表达式的汇编代码实现,结果存放在寄存器eax(如果是数据)或寄存器rax(如果是指针)中。
那些返回指针的操作类型为int*,因此涉及8字节操作(例如leaq)和寄存器(例如号rax)。最后一个例子表明可以计算同一个数据结构中的两个指针之差,结果的数据类型为long,值等于两个地址之差除以该数据类型的大小
3.8.3嵌套的数组
在这里插入图片描述
数组元素在内存中按照“行优先”的顺序排列,意味着第0行的所有元素,可以写作A[0]
在这里插入图片描述
3.8.4定长数组
C语言编译器能够优化定长多维数组上的操作代码。
在这里插入图片描述
(这个例子说明了一个很好的编码习惯。当程序要用一个常数作为数组的维度或者缓冲区的大小时,最好通过#define声明将这个常数与一个名字联系起来,然后在后面一直使用这个名字代替常数的数值。这样一来,如果需要修改这个值,只用简单地修改这个#define声明就可以了。)
在这里插入图片描述

这段代码包含很多聪明的优化。它去掉了整数索引j,并把所有的数组引用都转换成了指针间接引用
3.8.5变长数组
ISO C99引人了一种功能,允许数组的维度是表达式,在数组被分配的时候才计算出来。

在这里插入图片描述
它可以作为一个局部变量,也可以作为一个函数的参数,然后在遇到这个声明的时候,通过对表达式exp1和expr2求值来确定数组的维度。
动态的版本必须用乘法指令对i伸缩n倍,而不能用一系列的移位和加法。在一些处理器中,乘法会招致严重的性能处罚,但是在这种情况中无可避免。
在这里插入图片描述
图338b的代码保留了循环变量j,用以判定循环是否结束和作为到A的行i的元素组成的数组的索引。
可以看到,如果允许使用优化,GCC能够识别出程序访问多维数组的元素的步长然后生成的代码会避免直接应用等式(3.1)会导致的乘法。不论生成基于指针的代码(图3-37b)还是基于数组的代码(图338b),这些优化都能显著提高程序的性能。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值