我是MIPS的新手,我只是想知道,我通过以下方式存储空格字符:
li $t0, ' '
lb $t1, ' '
la $t2, myArray # load array
sb $t0, 0($t2) # myArray[0] = ' '
在这种情况下是$ t0 == $ t1? sb指令有效吗?我有点困惑的是我是否可以互换地使用字节和整数(单词)。
byte
与word
不能自由互换,因为byte只有8位信息,而word
是32位信息(在MIPS平台上)。因此,byte
可以设置为256个不同的可能值(8个0/1位值的28个组合),并且word
可以设置为2564个不同的可能值(32位模式)。
您需要四个字节来存储相同的可能信息量,例如您可以适合单个字(8位* 4 = 32位)。
但是,根据您正在处理的值,如果您可以保证它们的范围,您可以预测字节/半字/字之间的代码转换值如何表现,某些值是否会在没有任何损坏的情况下保持这种转换,或者它需要额外的验证/处理。例如,如果您的输入值是ASCII字符(来自字符串),那么这些只是7位(当解释为有符号整数时,仅在ASCII中定义值0到+127)。
因此,例如li $t0, ' '
将汇编为li $t0, 32
(因为“空格”字符在计算机中编码为值32)并且因为li
指令采用操作符号整数立即。
实际上“li”不是真正的MIPS指令,而是一个方便的伪指令,汇编器会将其转换为一个/两个本机指令来编码/组合所需的立即值。尝试使用值为+1,-1,+ 65000,-65000的li $t0, ...
示例,并在调试器中观察它如何组合成不同的本机指令,实现所需的“立即加载”效果,例如-65000值至少需要两个本机要编写的说明。
所以你在技术上将32位(字)值加载到$ t0(即使' '
只是值32
,它很容易适合字节)。
但是如你所知,你确实将ASCII“空间”加载到t0
中,无论t0
是32位“宽”,你知道它只足以将“byte”存储到内存中,如果你是在缓冲区中创建新的字符串,你想把空格字符放入其中。那么sb $t0, 0($t2)
是正确的。你在t0
中有一个更大的值,高24位被忽略,只有低8位的值用sb
指令写入内存(有效地“截断”内存中的那个值,它不可能从内存中读回完整的值,只有截断的部分)。
在MIPS汇编中,其他方向的转换也经常发生,因为例如lb
将只从存储器中读取8位,但它会将它们符号扩展为完整寄存器(32位)。如果你不注意你的价值观,你可能很容易陷入困境,例如:
.data
test_value: .byte 234
.text
li $t0, 234
lb $t1, test_value
tne $t0, $t1 # throw exception if t0 is not equal to t1
# terminate normally when values are equal
li $v0, 10
syscall
这可能看起来是第一次读取,因为它的值234与234相比,因此程序通常会终止,但如果你试图运行它,它将在tne
指令处以异常结束。因为当你将该位模式解释为“无符号8位整数”时,lb
对值进行符号扩展并且234
适合8位,如果将相同的位模式解释为“有符号8位整数”,则它变为值-22
。 -22
不等于234
。
你会将lb
指令更改为加载“无符号字节”的lbu
,代码将正常工作并正常退出,因为tne
将比较234和234值相等。
因此,在汇编编程时,您应该清楚地了解您处理的数据类型,并根据需要正确地扩展/截断这些值。
(顺便说一下,MARS汇编程序会警告你“234”不适合“有符号字节”和可能的截断 - 但是高达255的值实际上适合8位,只需要以“无符号”方式解释。高于255的值将得到真正被截断,就像有些位完全缺失一样,例如.byte 1025
将只在内存中存储值1
)