09 Communicating with People
最初,计算机只需要处理数字,但是很快,人们就发现计算机需要处理文本。最常用的表示文本的方式是 ASCII(American Standard Code for Information Interchange (ASCII)
),占用 8 个比特。
RISC-V 提供了高效处理字节的指令。lbu
(load byte unsigned
)是从内存取一个字节,放到寄存器最右端的八个比特。sb
(store byte
)将一个寄存器中最右端的八个比特存到内存中。
通常有三种方式表示字符串。1)以特殊的字符结尾,比如 C 语言中用 \0
结束;2)使用结构体,跟随字符串变量有一个长度变量;3)在字符串开头使用一定长度表示字符串长度,Java 就使用这种方式。
Compiling a String Copy Procedure, Showing How to Use C Strings
下面是 C 语言中经典的 strcpy
函数
void strcpy(char x[], char y[])
{
size_t i;
i = 0;
while ((x[i] = y[i]) != '\0') /* copy & test byte */
i += 1;
}
首先,我们假设 x, y
的基地址保存在寄存器 x10, x11
中,变量 i
使用 x19
,那么需要保存 x19
的值。
i = 0
,通过 0 加 0 把结果放到 x19
中。
接着循环开始。先计算 y[i]
的地址,结果放到 x5
中。
这里并没有将 i
的值乘以 4,因为 y
就是存放字节的数组。
下面把 y[i]
的内容加载到 x6
。
x[i]
的地址,结果放到 x7
,然后把 y[i]
,即 x6
的内容存到 x7
指向的内存上。
下面判断字符串是否结束了,如果结束了,准备退出函数。
如果没有跳转,即字符串没有结束,i++
,回到循环 L1
开始的地方。
最后是循环退出的部分,恢复 x19
和栈指针,然后返回。
L2: lw x19, 0(sp) // restore old x19
addi sp, sp, 4 // pop 1 word off stack
jalr x0, 0(x1) // return
strcpy
是一个叶子过程,没有再调用其他过程,那么编译器可以使用临时寄存器保存 i
的值,那样就不再需要保存和恢复 x19
寄存器的值。
在 Java 中,使用 16 比特长度的 Unicode 来表示字符串。为此,RISC-V 提供了加载和存储 16 比特信息的指令。16 比特称为半字(halfword
)。lhu
(load half unsigned
)从内存加载半字到寄存器的最右端 16 个比特,同时左边的比特位置零;lh
(load half
)类似,不过左边的比特位置符号位。sh
(store half
)取寄存器的最右端的 16 个比特信息写入内存。