如何简化基于井字棋胜负检查C代码实现的ARM汇编代码?
ARM井字棋胜负判断汇编代码简化方案
核心优化思路
- 消除重复内存加载:原代码每次判断都重新读取
player->state,实际上只需在函数开头读取1次存入通用寄存器即可,大幅减少冗余指令 - 用语义化标签替代硬编码跳转地址:原代码写死固定内存地址跳转,修改代码就要重新计算地址,用
.win、.next_check这类易懂的标签,新手也能一眼看懂逻辑 - 统一返回逻辑:原代码每次判断获胜都重复写
MOVS r0,#1 + 跳转返回,把返回逻辑收拢到函数末尾即可
简化后汇编代码(适配ARM Cortex-M系列,符合AAPCS调用约定)
player_won_asm: ; 输入:R0 = player_t 类型指针,player->state 是结构体第一个成员,偏移为0 ; 输出:R0 = 1 获胜,0 未获胜 MOVS R1, #0 ; R1 = 获胜标记,初始为0 LDRH R2, [R0, #0] ; 只读1次玩家状态存到R2,后续所有判断都复用R2的值 ; 判断第一行 掩码0x007 MOVS R3, #0x07 ANDS R3, R2, R3 CMP R3, #0x07 BEQ .win ; 判断第二行 掩码0x070 MOVS R3, #0x70 ANDS R3, R2, R3 CMP R3, #0x70 BEQ .win ; 判断第三行 掩码0x700 MOVW R3, #0x700 ANDS R3, R2, R3 CMP R3, #0x700 BEQ .win ; 判断第一列 掩码0x111 MOVW R3, #0x111 ANDS R3, R2, R3 CMP R3, #0x111 BEQ .win ; 判断第二列 掩码0x222 MOVW R3, #0x222 ANDS R3, R2, R3 CMP R3, #0x222 BEQ .win ; 判断第三列 掩码0x444 MOVW R3, #0x444 ANDS R3, R2, R3 CMP R3, #0x444 BEQ .win ; 判断正对角线 掩码0x124 MOVW R3, #0x124 ANDS R3, R2, R3 CMP R3, #0x124 BEQ .win ; 判断反对角线 掩码0x421 MOVW R3, #0x421 ANDS R3, R2, R3 CMP R3, #0x421 BNE .exit .win: MOVS R1, #1 .exit: MOVS R0, R1 BX LR
适合新手学习的补充说明
- 整个代码逻辑和你写的C代码完全一一对应,每一个判断分支对应C里的一个if条件,讲解的时候可以和C代码逐行对照,非常容易理解
- 没有用到任何复杂的ARM指令技巧,都是MOV、AND、CMP、跳转这类最基础的指令,适合初学者学习
- 如果要进一步简化代码行数,可以把8个获胜掩码存在常量数组里用循环判断,不过对新手来说顺序判断的版本逻辑更直观,没有循环的理解门槛
内容的提问来源于stack exchange,提问作者HermionEG
相关产品推荐
相关产品推荐

