汇编中如何通过多个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
关键修改点
- 移除输入换行符:通过循环查找缓冲区中的
0x0A,将其替换为空字符,避免输出时触发换行。 - 计算有效数字长度:循环统计到空字符的字节数,确保write只输出数字部分,不包含空字节和原换行符。
- 修正转换错误:将第二个数字的转换指令改为
sub ebx, '0',保证求和逻辑正确。 - 优化求和输出:针对两位数的求和结果,处理ASCII转换逻辑,同时缩小sum缓冲区的大小。
内容的提问来源于stack exchange,提问作者Josie
相关产品推荐
相关产品推荐

