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

x86 32位汇编程序输入结构体坐标后无法打印求技术指导

问题描述

我正在编写基于系统调用的x86 32位汇编程序,目标是创建Point结构体数组,通过用户输入填充每个结构体的x、y坐标。目前能将输入存入结构体,但无法正确打印坐标值。我知道输入需要转换才能正确输出,且printDec函数应处理该逻辑。

编译命令:

nasm -f elf Lab_14.asm -o Lab_14.o && gcc -m32 -g -lc Lab_14.o -o Lab_14

程序代码如下:

; Lab_14_Data_Structure

STRUC   Point       ;define Point structure
    .x: resb    4   ;reserve 4 bytes for x coordinate
    .y: resb    4   ;reserve 4 bytes for y coordinate
    .size:
ENDSTRUC

section .data
    msg1:       db  "Set the x and y coordinates of the five points",10,0
    msg1Len:    equ $-msg1
    
    msg2:       db  "Printing the X and Y coordinates for all points",10,0
    msg2Len:    equ $-msg2
    
    msg3:       db  "X = ",10,0
    msg3Len:    equ $-msg3
    
    msg4:       db  "Y = ",10,0
    msg4Len:    equ $-msg4
    
    msg5:       db  "Program completed successfully. Goodbye",10,0
    msg5Len:    equ $-msg5
    
    counter:    dd  5; keep track of how many input cycles are left
    
;declaring an instrance of Point structure and initalize its fields
P:ISTRUC Point
    AT Point.x, dd  0
    AT Point.y, dd  0
IEND

section .bss
PtArr:      resb    Point.size*5            ;reserve place for five structures
ArrCount:   equ ($-PtArr)/Point.size    ;five structures

section .text

    global main
    extern printf
    
main:
    ;start stack
    push    ebp
    mov ebp, esp
    
    mov ecx, ArrCount   ;count of array structures(5)
    mov esi, PtArr      ;points to beginning of array
    
    mov ecx, msg1
    mov edx, msg1Len
    call    PString

Input:
    ; get number from user to place in structures
    mov     ecx, msg3
    mov     edx, msg3Len
    Call PString
    
    mov eax, 3
    mov ebx, 0
    lea ecx, [esi+Point.x]
    mov edx, 4
    int 80h     
    
    mov     ecx, msg4
    mov     edx, msg4Len
    Call PString
    
    mov eax, 3
    mov ebx, 0
    lea ecx, [esi+Point.y]
    mov edx, 4
    int 80h
    
    add esi, Point.size     ;move to next structure in array
    dec DWORD[counter]
    cmp DWORD[counter], 0
    jne Input
    
        mov ecx, ArrCount   ;count of array structures(5)
    mov esi, PtArr      ;points to beginning of array
    mov DWORD[counter], 5   ;reset counter
PrintArray:
    mov eax, [esi+Point.x]
    call printDec
    call println

    mov eax, [esi+Point.y]
    call printDec
    call println
    
    add esi, Point.size
    dec DWORD[counter]
    cmp DWORD[counter], 0
    jne PrintArray
    
Exit:

    mov ecx, msg5
    mov edx, msg5Len
    call    PString
    
    mov esp, ebp
    pop ebp
    ret
    ;mov eax, 1
    ;mov ebx, 0
    ;int 80h

printDec:
    section .bss
        decstr      resb    10
        ct1     resd    1

    section .text
        pusha
        mov dword[ct1], 0
        mov edi, decstr
        add edi, 9
        xor edx, edx
    WhileNotZero:
        mov ebx, 10
        div ebx
        add edx, '0'
        mov byte[edi], dl
        dec edi
        inc dword[ct1]
        xor edx, edx
        cmp eax, 0
        jne WhileNotZero

        inc edi
        mov ecx, edi
        mov edx, [ct1]
        mov eax, 4
        mov ebx, 1
        int 80h

        popa
        ret

println:
    section .data
        nl  db  "",10
    section .text
        Pusha
        mov ecx, nl
        mov edx, 1
        mov eax, 4
        mov ebx, 1
        int 80h

        popa
        ret
        
PString:
    ;save register values
    pusha
    
    mov     eax, 4
    mov     ebx, 1
    int     80h
    
    ;restore old register values
    popa
    ret
问题分析与修复方案

核心问题是用户输入的是ASCII字符串,你直接将其作为整数存入结构体,而printDec函数把这些ASCII值当作十进制整数解析输出,导致打印结果混乱。此外代码存在段定义冗余、输入逻辑错误等细节问题,以下是具体修复步骤:

1. 添加ASCII转整数函数(atoi)

用户输入的是类似"123\n"的ASCII字符,需要转换为32位整数才能存入结构体。在.text段添加atoi函数:

; ASCII字符串转32位整数
; 输入:ecx=字符串地址,edx=读取的字节数
; 输出:eax=转换后的整数
atoi:
    push ebx
    push ecx
    push edx
    xor eax, eax        ; 初始化结果为0
    xor ebx, ebx
atoi_loop:
    mov bl, byte[ecx]
    cmp bl, '0'
    jb atoi_done        ; 遇到非数字字符停止转换
    cmp bl, '9'
    ja atoi_done
    sub bl, '0'         ; 字符转数字值
    imul eax, 10        ; 结果 *=10
    add eax, ebx        ; 累加当前数字
    inc ecx
    dec edx
    jnz atoi_loop
atoi_done:
    pop edx
    pop ecx
    pop ebx
    ret

2. 修改输入逻辑,使用临时缓冲区存储输入

在.bss段添加临时输入缓冲区:

section .bss
PtArr:      resb    Point.size*5
ArrCount:   equ ($-PtArr)/Point.size
input_buf:  resb    10  ; 临时存储用户输入的ASCII字符串

修改Input段的读取逻辑,先读入缓冲区再转换为整数:

Input:
    ; 获取X坐标输入
    mov ecx, msg3
    mov edx, msg3Len
    call PString
    
    ; 读取输入到临时缓冲区
    mov eax, 3
    mov ebx, 0
    mov ecx, input_buf
    mov edx, 10         ; 最多读取10字节(含换行)
    int 80h
    
    ; 转换为整数并存入Point.x
    mov ecx, input_buf
    mov edx, eax        ; sys_read返回的实际读取长度
    call atoi
    mov [esi+Point.x], eax
    
    ; 获取Y坐标输入
    mov ecx, msg4
    mov edx, msg4Len
    call PString
    
    mov eax, 3
    mov ebx, 0
    mov ecx, input_buf
    mov edx, 10
    int 80h
    
    call atoi
    mov [esi+Point.y], eax
    
    add esi, Point.size
    dec DWORD[counter]
    cmp DWORD[counter], 0
    jne Input

3. 修复函数内的段定义冗余

将printDec和println内的段定义移到全局段,避免重复定义:

  • 修改.bss段,添加decstr和ct1:
section .bss
; ... 原有内容 ...
decstr:     resb    10
ct1:        resd    1
  • 修改.data段,添加换行符nl:
section .data
; ... 原有内容 ...
nl:     db  10      ; 换行符
  • 简化printDec和println函数:
printDec:
    pusha
    mov dword[ct1], 0
    mov edi, decstr
    add edi, 9
    xor edx, edx
WhileNotZero:
    mov ebx, 10
    div ebx
    add edx, '0'
    mov byte[edi], dl
    dec edi
    inc dword[ct1]
    xor edx, edx
    cmp eax, 0
    jne WhileNotZero

    inc edi
    mov ecx, edi
    mov edx, [ct1]
    mov eax, 4
    mov ebx, 1
    int 80h

    popa
    ret

println:
    pusha
    mov ecx, nl
    mov edx, 1
    mov eax, 4
    mov ebx, 1
    int 80h
    popa
    ret

4. 修正提示字符串格式

将msg3和msg4中的换行符移到末尾,避免先换行再显示提示:

msg3:       db  "X = ",0
msg3Len:    equ $-msg3
msg4:       db  "Y = ",0
msg4Len:    equ $-msg4

5. 删除冗余代码

main开头的mov ecx, ArrCount被后续代码覆盖,可直接删除。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.11 08:50:32