assembly 在MIPS中打印出缓冲区

bnlyeluc  于 2023-10-19  发布在  其他
关注(0)|答案(1)|浏览(82)

我试图将基数为10的输入转换为二进制,并试图将其存储在input_buffer中,然后打印出input_buffer。当我尝试它不打印任何东西,如果它是空的参考这里是我有:

.data
ask_input: .asciiz "Enter a number (0-255): "
binary: .asciiz "\nThe number in base 2 is: "
input_buffer: .space 10

.text
.globl main

main:
    # Ask for input
    li $v0, 4
    la $a0, ask_input
    syscall

    # Assign input
    li $v0, 5
    syscall
    move $s0, $v0 # Integer is stored in $s0

    # Setup
    li $t0, 2    # For dividing by 2
    li $t1, 0    # For holding binary
    li $t2, 8    # Assume 8-bit binary response

    # Initialize the input_buffer with null bytes
    li $t3, 0      # Null byte
    li $t4, 10     # Number of bytes to initialize
    la $t5, input_buffer  # Address of input_buffer

    initialize_buffer:
        sb $t3, ($t5)   # Store a null byte
        addi $t5, $t5, 1  # Move to the next byte
        addi $t4, $t4, -1  # Decrement the byte count
        bnez $t4, initialize_buffer  # Continue until all bytes are null

convert_loop:
    # Continue the loop until $s0 is not equal to 0
    bnez $s0, continue_conversion

    # If $s0 is 0, jump to printing the binary
    j print_bin

continue_conversion:
    # Use 'and' with 1 for the least significant digit
    andi $t3, $s0, 1

    # Convert the least significant digit to '0' or '1'
    addi $t3, $t3, '0'

    # Store the ASCII character in input_buffer
    sb $t3, input_buffer($t2)

    # Right shift for division by 2
    srl $s0, $s0, 1

    # Decrement the counter
    addi $t2, $t2, -1

    # Continue the loop
    j convert_loop

print_bin:
    # Print the output message
    li $v0, 4
    la $a0, binary
    syscall

    # Print the binary representation stored in input_buffer
    li $v0, 4
    la $a0, input_buffer
    syscall

    # Exit
    li $v0, 10
    syscall
qyswt5oh

qyswt5oh1#

您将数字反向存储到缓冲区中-从缓冲区的末尾开始反向工作。当输入值变为0时,转换循环停止。因此,对于像3这样的输入值,它存储'1',然后'1',然后停止。缓冲区看起来像这样:

0   0   0   0   0   0x31 0x31 0
^               ^
input_buffer    t2 (as index)

然后从缓冲区的开头开始打印,缓冲区为null,因此当然不会打印任何内容。用于打印字符串的系统调用#4在它看到的第一个null处停止,即它打印一个以null结尾的字符串。如果系统调用忽略null,直到找到合适的字符来打印,然后荣誉null结束字符串,这将是愚蠢的,不是吗?原因是空字符串是一个有效的字符串,一个零长度的字符串,系统(系统调用,printf等)处理这一点非常正常。
要解决这个问题,你可以做以下 * 一 *(提示其中一个比其他的更容易):

  • 用空格0x 20而不是空值初始化缓冲区

这将打印前导空格后跟11,或者,

  • 打印缓冲区,不是从开始,而是从转换循环停止的地方开始

使用la $a0, input_buffer+1($t2),或者,

  • 将字符串从它被放入缓冲区的末尾复制到它的开头。

如果你做这个额外的复制,真的没有理由在转换中向后工作,因为可以向后复制。可能想使用一个单独的第二个缓冲区,但可以只使用一个缓冲区,如果小心边缘。但由于复印的原因,效率较低。
如果你把数据存储到缓冲区中,就没有必要用空值初始化它。如果您的算法精确地使用缓冲区,它将覆盖那里的任何旧值,即使程序在循环中运行用户输入,转换和输出。
但由于它不是在循环中运行,因此null初始化已经在程序加载到内存中时完成,因为.space指令指示了这一点。当然,这只会在节目开始时进行一次。(虽然正如我所说的,如果你正确使用缓冲区,任何新的输出都会覆盖旧的输出,从而避免了空字节的初始化。)
在以下

addi $t5, $t5, 1  # Move to the next byte

这应该使用addiu而不是addi,因为这是指针运算,而指针运算是无符号整数运算。使用addi有符号溢出异常的风险,这不仅不相关,而且对于无符号算术是错误的。但是,考虑到数据的起始地址和范围,这个问题不会出现。如果你的程序正在使用堆,并且使用了很多堆,这个逻辑错误可能会显示出来(作为一个不需要的异常,停止程序)。

相关问题