80x86汇编与C语言-4
看清C代码每行对应的汇编指令,掌握函数调用与栈帧布局
按 空格/→ 演示下一步
全部页面点击任意一页,跳回舞台从这页播放
80x86汇编与C语言-4
看清C代码每行对应的汇编指令,掌握函数调用与栈帧布局
数组的存储
在C里写 int a[5],用 a[i] 取值很简洁。但CPU不懂「数组」——它只认内存地址。这一页拆开看:编译器把你的数组翻成什么内存布局,CPU又怎么算出每个元素的地址。
房间等大且相邻,房号=起始房号+序号×单房宽度,楼层对应基地址
数组的访问-1
上一页我们看到数组在内存里排成一长串——但 CPU 执行 a[3] 时,它不会自动跳到第三个位置。它只认地址,必须把下标翻译成具体地址才能取到数。
影院地址=基址,排号=下标,排距=元素大小,座位左右偏移=disp
数组的访问-2
上页算出元素地址=基础地址+偏移,但C里写a[i]就拿到值——背后是指针算术。指针+1不是加一字节,而是跨过一个元素,汇编用一条寻址指令就能完成。
第5座=第1座起点+4×每座宽度,scale 就是每座宽度
数组的访问-3
前两页我们看到 a[i] 就是「首地址 + 偏移」。但遇到二维数组 a[i][j],CPU 怎么一步算出地址?这就涉及到行主序约定和地址公式。
先确定第几排(i × 每排座位数),再数第几个座位(j),偏移量自然算出
数组的访问-4
前几页默认每个元素 1 字节。但 short 是 2、int 是 4、long 是 8——汇编怎么用同一个公式访问任意大小?这就靠 80x386 引入的「比例因子」。
想拿第 N 格的书,得先知道单本多厚,位置 = 起点 + N × 厚度
数组的访问-5
前面看到C的arr[i]会被编译成一条mov指令。但80x86具体用哪种寻址来编码?这关系到代码大小和执行速度——今天看SIB字节和比例因子是怎么被'精打细算'选出来的。
厅号+排号×每排数+座号,三项相加锁定一个具体观众
二维数组示例-1
上几页我们把一维数组摸透了——一段连续内存加下标算偏移。那二维数组呢?比如一张成绩表、一个图像像素矩阵,内存里它是怎么摆的?
座位号连续:1排1号…1排N号,接着才是2排1号…数组也是这样展开
二维数组示例-2
上一页用二维表理解 a[i][j],但内存是线性的,C 按行连续排列,这决定了所有寻址方式。
先按楼层找排再按位置找座:地址 = 楼号×每排座位数 + 座号
二维数组示例-3
示例-2 揭示了二维数组在内存里是连续排列的。那 C 写 a[i][j] 时,编译器到底怎么把这两个下标翻译成线性地址?
先跳几整排(i × 列数),再从该排头数 j 个座位
本节要点
- ✓数组在内存中是连续等长的数据块
- ✓元素地址=基址+索引×元素宽度,汇编需按宽度缩放
- ✓二维数组按行主序连续存放,可展平为一维看待
- ✓C不做越界检查,汇编必须由程序员核对索引范围
- ✓循环遍历时指针自增比反复计算下标更高效
课后思考
先独立思考再对照参考答案。三个问题分别检验核心理解、汇编应用与越界边界。
参考答案a[i] 等价于 *(a + i)。从0开始时偏移量就是 i*sizeof(元素);若从1开始则要先减1,多一条运算指令。0起点还让首元素地址与数组名一致,惯例沿用至今。
参考答案按行遍历时内层循环只调整列偏移,访存地址连续;按列遍历每次跳一整行长度。汇编上对应不同的基址更新方式,连续访问更利于CPU预取与缓存命中。
参考答案汇编里没有'数组'概念,只有基址加偏移寻址。越界只是算出一个错误地址,可能踩到栈上返回地址、相邻变量或函数指针,经典栈溢出攻击即源于此。