2.9 人机交互
ASCII与二进制
对应表略
字节转移指令
lbu:加载无符号字节,从内存中加载1个字节,放在寄存器最右边8位。
sb:存储字节指令,从寄存器的最右边取1个字节并将其写入内存。
复制1个字节顺序如下:
lbu x12, 0(x10) //读取x10中地址值对应的字节,写入x12的低8位
sb x12, 0(x11) //将x12中的值的低8位写入x11对应的地址内存
字符通常组合成具有可变数量的字符串。字符串表示有三种选择:
- 字符串的第一个位置,用于给出字符串的长度
- 附加带有字符串长度(如在结构体中)的变量。
- 字符串的最后位置用一个字符标记字符串结尾。
C语言使用第三种选择,使用值为0的字节终止字符串(ASCII中为null)
Java使用第一个选择。
C语言中字符串“Cal”用4个字节表示:十进制 67,97,108,0
例题:编译字符串复制程序,展示如何使用C语言字符串
void strcpy(char x[], char y[]){size_t i;i = 0;while((x[i]=y[i])!='\0')i += 1;
}
答案:下面是基本的RISC-V汇编代码段
strcpy://数组x,y基址分别存放x10,x11中,i在x19寄存器中addi sp, sp, -4 //1个字的指针sw x19, 0(sp) //i在x19寄存器中,保存19寄存器到栈中add x19, x0, x0 //i = 0 + 0,将i初始化为0
L1: add x5, x19, x11 //y[i]地址在x5中,通过y首地址+i来组成lbu x6, 0(x5) //x6 = y[i],使用无符号加载字节,将字符放入x6中add x7, x19, x10//x[i]地址在x7中sb x6, 0(x7) //将x6的值写入x7地址所在内存中beg x6, x0, L2 //如果字符串最后一个字符是0,退出addi x19, x19, 1 //i = i + 1jal x0, L1
L2: lw x19, 0(sp) //存回旧的x19addi sp, sp, 4 //弹出1字的栈jalr x0, 0(x1) //返回程序
在C语言中字符串复制通常使用指针而不是数组,以避免在上面代码中对i进行操作。
以上过程是一个叶程序,编译器可以将i分配给临时寄存器并避免保存和恢复x19,当编译器找到一个叶过程时,它会在使用必须保存的寄存器之前耗尽所有的临时寄存器。
Java中的字符和字符串
Java用Unicode,16位表示1个字符。加载半字(lh),存储半字(sh)。
字符串是Java类,由多个方法,包含字符串长度的字,类似于Java数组。
详细阐述
RISC-V需要保持栈的四字(16字节),地址对齐,以获得更好的性能。
意味着栈上分配的char变量可能多达16个字节,即使不需要这么多。
C会把字符串变量或字节型数组每16个字节压缩为四字,Java字符串变量或short数组将每8个半字压缩为四字。