You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

AArch64 GNU AS汇编计算器:输入转十进制与校验问题求助

AArch64汇编计算器:输入校验与转换修复

核心问题分析

你的代码存在几个关键错误,导致无法正确校验输入字符和转换数字:

  • 错误地将内存地址当作输入字符值进行运算/比较
  • 读取输入时的长度与分配的内存不匹配,导致数据溢出
  • 未正确使用单字节加载指令读取字符类型数据

具体修复步骤

1. 修复运算符读取与校验

  • 读取运算符时,只读取1字节(匹配.skip 1的内存分配),然后读取换行符丢弃
  • 使用ldrb加载单字节字符,而非ldr(会读取4字节,导致错误数据)
  • 直接与运算符的ASCII值(如'+')进行比较,而非错误的地址运算

2. 修复数字输入转换与校验

  • 将输入的ASCII字符串转换为整数时,需遍历每个字符,校验是否在'0'到'9'之间
  • 转换逻辑:初始化结果为0,每个字符减'0'后,结果 = 结果*10 + 该值

3. 修复输入处理逻辑

  • 读取输入后,利用exit_err分支处理非法输入的情况

修改后的完整代码

.global main

.section .data

op_plus: .byte '+'
op_minus: .byte '-'
op_mul: .byte '*'
op_div: .byte '/'

temp: .skip 1

debug_msg1: .asciz "True\n"
debug_msg1_len = . - debug_msg1

message_0: .asciz "Hello, World!\n"
message_0_len = . - message_0

message_1: .asciz "Enter mode +,-,*,/: "
message_1_len = . - message_1

message_2: .asciz "enter the first num: "
message_2_len = . - message_2

message_3: .asciz "enter the second num: "
message_3_len = . - message_3

message_4: .asciz "result is "
message_4_len = . - message_4

err_msg: .asciz "Invalid input!\n"
err_msg_len = . - err_msg

.section .bss
    .lcomm num1, 10
    .lcomm num2, 10
    operator: .skip 1

.section .text

main:
    // 打印欢迎信息
    ldr x1, =message_0
    ldr x2, =message_0_len
    bl print
    
    // 提示输入运算符
    ldr x1, =message_1
    ldr x2, =message_1_len
    bl print

    // 读取运算符(仅1字节)
    ldr x1, =operator
    ldr x2, =1
    bl input
    // 检查是否读取成功
    cmp w0, 1
    bne exit_err

    // 读取并丢弃换行符
    ldr x1, =temp
    ldr x2, =1
    bl input

    // 校验运算符
    ldrb w0, [x1, -1]  // 回到operator地址
    cmp w0, '+'
    beq add_mode
    cmp w0, '-'
    beq sub_mode
    cmp w0, '*'
    beq mul_mode
    cmp w0, '/'
    beq div_mode
    // 非法运算符,报错退出
    bl exit_err

add_mode:
    // 提示输入第一个数字
    ldr x1, =message_2
    ldr x2, =message_2_len
    bl print
    ldr x1, =num1
    bl read_and_convert_num
    mov w19, w0  // 保存第一个数字到w19

    // 提示输入第二个数字
    ldr x1, =message_3
    ldr x2, =message_3_len
    bl print
    ldr x1, =num2
    bl read_and_convert_num
    mov w20, w0  // 保存第二个数字到w20

    // 计算加法
    add w21, w19, w20
    bl print_result
    bl exit

// 其他运算模式可参照add_mode实现,此处省略sub/mul/div
sub_mode:
    bl exit_err
mul_mode:
    bl exit_err
div_mode:
    bl exit_err

// 读取数字字符串并转换为整数,同时校验输入
// x1: 输入缓冲区地址,返回w0: 转换后的整数
read_and_convert_num:
    mov w0, 0  // 初始化结果为0
    mov x2, x1  // 保存缓冲区起始地址

read_loop:
    ldrb w3, [x1], 1  // 读取一个字符,地址自增
    cmp w3, '\n'  // 遇到换行符结束
    beq convert_done
    // 校验是否为数字
    cmp w3, '0'
    blt exit_err
    cmp w3, '9'
    bgt exit_err
    // 转换:result = result*10 + (char - '0')
    sub w3, w3, '0'
    mov w4, 10
    mul w0, w0, w4
    add w0, w0, w3
    b read_loop

convert_done:
    ret

// 打印结果
print_result:
    ldr x1, =message_4
    ldr x2, =message_4_len
    bl print
    // 将整数转换为字符串并打印(此处简化,可实现itoa函数)
    // 暂用debug输出,实际需实现整数转字符串
    ldr x1, =debug_msg1
    ldr x2, =debug_msg1_len
    bl print
    ret

print:
    mov x0, 1  // STDOUT
    mov w8, 64  // sys_write
    svc #0
    ret

input:
    mov x0, 0  // STDIN
    mov w8, 63  // sys_read
    svc #0
    ret

exit_err:
    ldr x1, =err_msg
    ldr x2, =err_msg_len
    bl print
    mov w8, 93
    mov x0, 1  // 错误退出码
    svc #0

exit:
    mov w8, 93
    mov x0, 0  // 正常退出码
    svc #0

对之前尝试方法的解释

  1. sub {register},{register}, '0'无效:你操作的是内存地址(如x1存的是operator的地址),而非输入的字符值,且用了ldr读取4字节而非ldrb读取单字节字符。
  2. cmp {register}, {value}无效:同样是把地址当作字符值比较,完全不匹配,需先读取字符到寄存器再比较。
  3. 输入长度设为1无效:未校验read的返回值确认是否读取成功,且未正确处理后续的换行符,导致残留的换行符影响后续输入。

内容的提问来源于stack exchange,提问作者Atonix_

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.11 00:23:12