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

汇编中如何通过多个write系统调用输出无换行的连续文本?

如何用多个write系统调用实现无换行的连续文本输出

我希望输出一行格式如下的内容:

<num>和<num2>的和是<sum>

但实际运行代码后,输出分成了三行:

Enter a number: 1
Enter a second number: 2
The sum of 1
    and 2
    equals 3

我的原代码如下:

section .data                           ;Data segment
   userMsg db 'Enter a number: ' ;Ask the user to enter a number
   lenUserMsg equ $-userMsg             ;The length of the message
   userMsg2 db 'Enter a second number: ' ;Ask the user to enter a number
   lenUserMsg2 equ $-userMsg2             ;The length of the message
   dispMsg db 'The sum of '
   lenDispMsg equ $-dispMsg         
   dispMsg2 db ' and '
   lenDispMsg2 equ $-dispMsg2
   dispMsg3 db ' equals '
   lenDispMsg3 equ $-dispMsg3

section .bss           ;Uninitialized data
   num resb 5
   num2 resb 5
   sum resb 5
    
section .text          ;Code Segment
   global _start
    
_start:                ;User prompt
   mov eax, 4
   mov ebx, 1
   mov ecx, userMsg
   mov edx, lenUserMsg
   int 80h

   ;Read and store the first user input
   mov eax, 3
   mov ebx, 2
   mov ecx, num  
   mov edx, 5          ;5 bytes (numeric, 1 for sign) of that information
   int 80h
   
   ;Second user input
   mov eax, 4
   mov ebx, 1
   mov ecx, userMsg2
   mov edx, lenUserMsg2
   int 80h

   ;Read and store the second user input
   mov eax, 3
   mov ebx, 2
   mov ecx, num2  
   mov edx, 5
   int 80h
    
   ;'The sum of '
   mov eax, 4
   mov ebx, 1
   mov ecx, dispMsg
   mov edx, lenDispMsg
   int 80h  
   
   ;num
   mov eax, 4
   mov ebx, 1
   mov ecx, num  
   mov edx, 5
   int 80h
   
   ;' and '
   mov eax, 4
   mov ebx, 1
   mov ecx, dispMsg2
   mov edx, lenDispMsg2
   int 80h  
   
   ;num2
   mov eax, 4
   mov ebx, 1
   mov ecx, num2  
   mov edx, 5
   int 80h
   
   ;' equals '
   mov eax, 4
   mov ebx, 1
   mov ecx, dispMsg3
   mov edx, lenDispMsg3
   int 80h  

   ;Add the inputs
   mov eax, [num]
   sub eax, '0' ;convert from ASCII to decimal
   mov ebx, [num2]
   sub eax, '0'
   add eax, ebx
   add eax, '0'
   mov [sum], eax

   ;Print the sum
   mov eax, 4
   mov ebx, 1
   mov ecx, sum
   mov edx, 5
   int 0x80
    
   ; Exit code
   mov eax, 1
   mov ebx, 0
   int 80h

问题根源

换行的核心原因是read系统调用会把用户输入时按下的回车键(ASCII码0x0A,即换行符)也读取到缓冲区中。比如输入1后按回车,num缓冲区里的内容是'1' + '\n' + 三个空字节,输出时整个5字节被打印,换行符就触发了换行。

另外原代码还有一个计算错误:转换第二个数字时,错误地用了sub eax, '0',应该是sub ebx, '0',否则第二个数字的转换会失效,导致求和结果错误。

修正方案

我们需要在读取输入后,找到缓冲区里的换行符并替换为空字符,同时计算有效数字的长度,确保write系统调用只输出数字部分。下面是修改后的代码:

section .data                           ;Data segment
   userMsg db 'Enter a number: '
   lenUserMsg equ $-userMsg
   userMsg2 db 'Enter a second number: '
   lenUserMsg2 equ $-userMsg2
   dispMsg db 'The sum of '
   lenDispMsg equ $-dispMsg         
   dispMsg2 db ' and '
   lenDispMsg2 equ $-dispMsg2
   dispMsg3 db ' equals '
   lenDispMsg3 equ $-dispMsg3

section .bss           ;Uninitialized data
   num resb 5
   num2 resb 5
   sum resb 2  ; 单个数字求和最大为18,仅需2字节
    
section .text          ;Code Segment
   global _start
    
_start:                
   ; 提示输入第一个数字
   mov eax, 4
   mov ebx, 1
   mov ecx, userMsg
   mov edx, lenUserMsg
   int 80h

   ; 读取第一个输入
   mov eax, 3
   mov ebx, 2
   mov ecx, num  
   mov edx, 5
   int 80h
   
   ; 移除第一个输入的换行符
   mov esi, num
remove_newline1:
   cmp byte [esi], 0x0A  ; 查找换行符
   jz replace_with_null1
   inc esi
   jmp remove_newline1
replace_with_null1:
   mov byte [esi], 0x00  ; 替换为空字符
   
   ; 提示输入第二个数字
   mov eax, 4
   mov ebx, 1
   mov ecx, userMsg2
   mov edx, lenUserMsg2
   int 80h

   ; 读取第二个输入
   mov eax, 3
   mov ebx, 2
   mov ecx, num2  
   mov edx, 5
   int 80h
   
   ; 移除第二个输入的换行符
   mov esi, num2
remove_newline2:
   cmp byte [esi], 0x0A
   jz replace_with_null2
   inc esi
   jmp remove_newline2
replace_with_null2:
   mov byte [esi], 0x00
   
   ; 输出 "The sum of "
   mov eax, 4
   mov ebx, 1
   mov ecx, dispMsg
   mov edx, lenDispMsg
   int 80h  
   
   ; 计算第一个数字的长度并输出
   mov esi, num
   mov edx, 0
count_num_len:
   cmp byte [esi], 0x00
   jz end_count_num
   inc edx
   inc esi
   jmp count_num_len
end_count_num:
   mov eax, 4
   mov ebx, 1
   mov ecx, num
   int 80h
   
   ; 输出 " and "
   mov eax, 4
   mov ebx, 1
   mov ecx, dispMsg2
   mov edx, lenDispMsg2
   int 80h  
   
   ; 计算第二个数字的长度并输出
   mov esi, num2
   mov edx, 0
count_num2_len:
   cmp byte [esi], 0x00
   jz end_count_num2
   inc edx
   inc esi
   jmp count_num2_len
end_count_num2:
   mov eax, 4
   mov ebx, 1
   mov ecx, num2
   int 80h
   
   ; 输出 " equals "
   mov eax, 4
   mov ebx, 1
   mov ecx, dispMsg3
   mov edx, lenDispMsg3
   int 80h  

   ; 计算两个数字的和
   mov eax, [num]
   sub eax, '0'
   mov ebx, [num2]
   sub ebx, '0'  ; 修正转换错误
   add eax, ebx
   
   ; 将和转换为ASCII(支持两位数)
   mov esi, sum
   mov ecx, 10
   xor edx, edx
   div ecx
   cmp eax, 0
   jz write_single_digit
   add eax, '0'
   mov [esi], al
   inc esi
write_single_digit:
   add edx, '0'
   mov [esi], dl
   inc esi
   mov byte [esi], 0x00  ; 添加结束符
   
   ; 输出和
   mov eax, 4
   mov ebx, 1
   mov ecx, sum
   mov edx, 2
   int 0x80
   
   ; 输出换行符,让终端提示符在新行
   mov eax, 4
   mov ebx, 1
   mov ecx, 0x0A
   mov edx, 1
   int 80h
    
   ; 退出程序
   mov eax, 1
   mov ebx, 0
   int 80h

关键修改点

  1. 移除输入换行符:通过循环查找缓冲区中的0x0A,将其替换为空字符,避免输出时触发换行。
  2. 计算有效数字长度:循环统计到空字符的字节数,确保write只输出数字部分,不包含空字节和原换行符。
  3. 修正转换错误:将第二个数字的转换指令改为sub ebx, '0',保证求和逻辑正确。
  4. 优化求和输出:针对两位数的求和结果,处理ASCII转换逻辑,同时缩小sum缓冲区的大小。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.29 01:17:07