中央处理器每执行一条机器指令,本质是在告诉硬件"对谁、做什么"。一条指令在二进制层面通常被拆成两段:前段是操作码,用来指明这条指令要完成什么动作,例如加法、传送、比较、转移;后段是地址码,用来指明参与运算的操作数或者操作数所在的位置。软考上午题常给出"某机字长十六位、操作码占四位、地址码占若干位"的指令格式,让考生推断寻址能力或访存次数,考查的正是地址码与寻址方式之间的约束关系。理解这一点后,再看"字长"与"指令长"的区别就清晰了:机器字长是中央处理器一次能处理的二进制位数,与数据通路宽度相关;指令长是单条指令占用的位数,可以等于、小于或大于字长。指令长越长,能塞下的操作码与地址码越宽,可编码的寻址方式也就越多,但取指访存的次数与指令体积也随之上升,软考常把这两组概念放在同一题里联合考查。
值得强调的是,地址码里写的不一定是"操作数本身",也不一定是"操作数的内存地址",它可能是寄存器编号、可能是位移量、也可能干脆是操作数本身。决定这几种可能性的,就是寻址方式。可以说,寻址方式是连接"指令中的形式信息"与"真正参与运算的操作数"之间的翻译规则。
学习寻址方式必须区分两个术语。形式地址,是指令地址码字段中直接给出的那个数,记作 A;有效地址,是中央处理器经过寻址方式换算之后,最终得到的、能唯一定位一个操作数的地址,记作 EA。形式地址只是"线索",有效地址才是"答案"。例如直接寻址中 EA 就等于 A,二者数值相同;但在间接寻址中,EA 等于以 A 为地址的那个存储单元里存放的内容,A 与 EA 天差地别。
历年真题几乎都会隐含考查这一区分。题目若问"该指令操作数的有效地址是多少",考生必须先判断寻址方式,再按对应公式把 A 翻译成 EA,绝不能把形式地址直接当成有效地址作答。
指令执行总要先把指令本身从内存取到控制器,这一步叫取指,固定访存一次。麻烦在取操作数:不同寻址方式下,中央处理器为了拿到操作数,需要再去内存取几次,次数并不相同。立即寻址的操作数就在指令里,取指即得到,无需再访存;直接寻址要按 A 去内存取一次操作数;一次间址要先用 A 去内存取有效地址,再用该地址去内存取操作数,共两次;寄存器寻址操作数在寄存器,零次访存。
访存次数直接决定指令执行速度,这是命题人把"寻址方式"与"性能"绑在一起考的底层逻辑。考生在算总访存次数时,第一容易漏掉取指那一次,第二容易在间接寻址时少算一级,这两处恰恰是送分题变丢分题的高频位置。
立即寻址的特点是,指令的地址码字段给出的不是地址,而是操作数本身(或者说,经极小处理就是操作数)。执行时不需要再去内存取操作数,取指动作完成的同时操作数已经就位。它的优势是执行最快、无需额外访存;劣势是操作数大小受地址码位数限制,且操作数被"写死"在指令中,运行期间无法修改,因此常用于给寄存器赋常数、设置初值、做比较基准等场景。编译器中把常量直接拼进指令、把零寄存器用异或清零等优化,背后都藏着立即寻址的身影。由于立即数随指令一同取入,指令字长也会因容纳立即数而变长,程序整体体积随之增大,这也是“以空间换时间”的一种具体表现。
软考易错点在于:有人把立即寻址理解成"地址码就是地址",这是错误的。立即寻址中地址码即数据,不存在任何"按地址去找"的过程。考题若说"指令中给出了操作数的地址",那一定不是立即寻址。另一个常考的点是立即数的表示范围:立即数宽度受地址码位数限制,若地址码为八位且用补码表示,则能直接给出的立即数范围是负一百二十八到正一百二十七。超出这个范围的常数,编译时要么拆成多条指令,要么先送入寄存器再参与运算,这正说明立即寻址"快但受限"的双面性。
寄存器寻址是指,指令地址码给出的是寄存器编号,真正的操作数就存放在这个通用寄存器里。由于寄存器在 CPU 内部,访问它不需要访问内存,因此也几乎不增加访存开销,执行速度仅次于立即寻址。它在编译生成的目标代码中极为常见,比如把变量放进寄存器做累加。地址码的位数决定了可选寄存器的数量:地址码若为三位,最多对应八个寄存器;若为四位,则最多十六个。软考有时会结合"通用寄存器组"问可寻址的寄存器个数,考生只需把地址码位数按二的幂换算即可。寄存器寻址之所以快,还在于它不经过地址总线与数据总线的内存往返,完全在 CPU 内部完成,因此指令周期中不包含访存阶段,这也是它与直接寻址在时序上的本质差异。
与立即寻址的区别要记牢:立即寻址的地址码是"值",寄存器寻址的地址码是"寄存器号",操作数在寄存器里而非指令里。软考偶尔会拿这两类混着考,问"哪种寻址方式操作数在指令中",答案只能是立即寻址。
直接寻址的规则最简单:有效地址 EA 等于形式地址 A,即指令地址码里写的那个数就是操作数在内存中的位置。执行时,取指之后按 A 去内存取一次操作数即可。它直观、好理解,但寻址范围被指令中地址码的位数死死限制,例如地址码六位,则最多访问六十四个存储单元,难以应对大内存。此外,直接寻址还有一个局限:地址一经写入指令便固化,程序若要访问不同位置的数据,就必须改写指令本身,这不利于代码共享与复用。相比之下,后面要讲的基址、变址、间接等寻址方式,本质上都是在想办法把"写死在指令里的地址"变成"运行时可变的地址",从而换取灵活性或更大的寻址空间。理解这一动机,才能明白为什么机器要设计出这么多寻址方式,而不是只有直接寻址一种。
直接寻址在考试中常与"寻址范围计算"绑定:给定地址码位数 n,直接寻址可访问的主存单元数就是二的 n 次方。这一步往往就是选择题的前半问。还需留意一个隐含条件:地址码位数与存储单元的编址方式共同决定可访问的"字节数"。若机器按字节编址、地址码 n 位,则可访问二 n 次方个字节;若按字编址,则同样位数可访问的是二 n 次方个字,二者在题目给出的"寻址范围是多少字节"问法下会差出数倍,考生务必看清编址单位再换算。
间接寻址中,形式地址 A 指向的那个内存单元里存放的,并不是操作数,而是操作数的有效地址。换句话说,EA 等于以 A 为地址取出来的内容。它的价值在于突破直接寻址的范围限制:哪怕指令地址码只有六位,只要内存地址是十六位,间接寻址就能借助那十六位的"地址字"访问到整个六十四 K 空间。程序中指针、动态数据结构常借间接寻址实现。
代价是访存次数增加:先按 A 取一次得到 EA,再按 EA 取一次得到操作数,共两次。若允许多重间接,访存次数还会继续累加,直到碰到约定的结束标志。考题若问"一次间接寻址共访存几次(含取指)",答案是取指一次加取 EA 一次加取操作数一次,共三次,漏算极易出错。为了区分"间接"的层级,教材通常约定:地址字的高位或特定位作为间址标志,读到该位为一时表示还需继续间接寻址,为零时才表示当前取出的已是真正的有效地址。理解这一标志位机制,多重间址的访存次数就可以按"标志为一就多一次"的规则逐步累加。
寄存器间接寻址把间接寻址中的"地址字"放到寄存器里:EA 等于指定寄存器的内容,操作数在内存中。它兼具间接寻址扩大范围的能力与寄存器访问的快捷,访存一次即可取到操作数(取指另算)。在遍历数组、访问链表节点时,让寄存器保存当前指针,每步更新寄存器内容,就能高效移动访问位置。
它与寄存器寻址仅一字之差,区别在"操作数在寄存器里"还是"寄存器里放的是地址"。这一字之差,在真题里就是两个不同的选项。寄存器间接寻址的一个典型应用是数据块搬运:把源指针和目标指针分别放进两个寄存器,用一条传送指令配合寄存器自增,就能逐单元搬完整个数据块,既扩大了寻址范围,又保持了单次访存取数的效率,是间接寻址思想在工程实践中的最佳落点。
基址寻址的有效地址等于基址寄存器的内容加上形式地址中的位移量,即 EA 等于 BR 加 A。基址寄存器通常由操作系统在程序装入时设定,内容是该程序在主存中的起始位置,用户程序不可随意修改。这样一来,程序内部都用从零开始的相对地址编写,装入内存时只要把基址寄存器设为实际起始地址,全部指令的有效地址自动整体平移,无需改动指令本身,多道程序环境下的程序重定位因此变得简单可靠。
软考重在区分"谁改基址寄存器":基址寄存器
本篇完!