lbu
lbu
rd, off(rs1)
rd = mem[rs1 + off]
R
31–25funct7
24–20rs2
19–15rs1
14–12funct3
11–7rd
6–0opcode
I
31–20imm[11:0]
19–15rs1
14–12funct3
11–7rd
6–0opcode
S
31–25imm[11:5]
24–20rs2
19–15rs1
14–12funct3
11–7imm[4:0]
6–0opcode
B
31–25imm[12,10:5]
24–20rs2
19–15rs1
14–12funct3
11–7imm[4:1,11]
6–0opcode
U
31–12imm[31:12]
11–7rd
6–0opcode
J
31–12imm[20,10:1,11,19:12]
11–7rd
6–0opcode

lbu loads one byte (8 bits) from memory and treats it as unsigned. It is the companion to lb, differing only in how it fills the rest of the register. Both read a single byte with the same lbu rd, offset(rs1) addressing; the lb page introduces bytes and the addressing form.

A register holds 32 bits, so loading 1 byte leaves 24 to fill. lb copies the byte's top bit across them (sign-extension, which can produce a negative number); lbu fills them with 0s instead, so the result is always a plain value from 0 to 255. The u marks this unsigned reading.

This is the everyday choice for working with text. Character codes are unsigned, and many of them have their top bit set — accented letters and various symbols — so loading them with the sign-extending lb would turn them negative and break comparisons. The standard loop for walking through text uses lbu: load a byte, check whether it is zero (the marker for the end of the text), process it, advance the address by 1, and repeat.

Beyond text, lbu suits any byte-by-byte data: color channels in images, raw data buffers, instruction bytes in an interpreter. Because the bytes come in clean with no sign confusion, they also combine neatly with shifts and ORs when you need to rebuild a larger value out of individual bytes. Use lb only when the 8-bit data is genuinely signed.