ASCII and character encoding
How text becomes numbers
ASCII is a character encoding that assigns every letter, digit, punctuation mark, and control code a 7-bit number from 0 to 127, so text is stored as a sequence of byte codes: 'A' is 65 (0x41), '0' is 48 (0x30), and 'a' is 97 (0x61).
You can read a row of bits as a binary number and write it compactly in hexadecimal. But a computer's memory holds only numbers, so how does it store the letter
A, or a comma, or a space? The answer is a codebook: agree on a number for every character, and text becomes a list of those numbers. ASCII (the American Standard Code for Information Interchange) is the classic codebook, and it is the reason A is stored as the number 65. Encode any text to its ASCII bytes (and back) with the text to binary tool.Think of a hotel with numbered rooms. The guest in room
65 is the character A; room 97 holds a; room 48 holds the digit character 0. Storing the word Hi is just writing down its room numbers in order. Nothing about the bits *looks* like a letter; the meaning is entirely the shared agreement that code 65 means A. Look up any character, code, or control name in the ASCII table.One number per character (7 bits, 128 codes)
ASCII uses 7 bits, so it has
2^7 = 128 codes, numbered 0 to 127. That is enough for the uppercase letters, the lowercase letters, the ten digit characters, common punctuation, and a block of invisible control codes (like newline and tab). Each character maps to exactly one code, and each code to one character. In practice a character is stored in a whole byte (8 bits) with the top bit b7 left 0, so an ASCII code always looks like 0xxx xxxx.| character | decimal | hex | binary (byte) |
|---|---|---|---|
| NUL | 0 | 0x00 | 0000 0000 |
| LF (newline) | 10 | 0x0A | 0000 1010 |
| space | 32 | 0x20 | 0010 0000 |
| 0 | 48 | 0x30 | 0011 0000 |
| 9 | 57 | 0x39 | 0011 1001 |
| A | 65 | 0x41 | 0100 0001 |
| Z | 90 | 0x5A | 0101 1010 |
| a | 97 | 0x61 | 0110 0001 |
| z | 122 | 0x7A | 0111 1010 |
0 to 31 are invisible control codes (NUL is 0, newline LF is 10). The printable characters start at space (32). Notice the byte's top bit is always 0: an ASCII code never exceeds 0111 1111 (127).The ranges are laid out on purpose
ASCII is not a random shuffle. The characters are grouped into tidy, contiguous ranges, and the gaps between the ranges are chosen so common conversions become simple arithmetic:
- Control codes
0to31(0x00to0x1F): non-printing signals likeNUL(0), tab (9), and newlineLF(10). - Digits
'0'to'9'are48to57(0x30to0x39): consecutive, in order. - Uppercase
'A'to'Z'are65to90(0x41to0x5A). - Lowercase
'a'to'z'are97to122(0x61to0x7A), sitting exactly32codes above their uppercase twins.
The case bit and the digit trick
Because uppercase starts at
65 and lowercase starts at 97, every letter's two cases differ by exactly 32, which is 0x20. And 32 is 2^5, so it is a single bit: bit 5. Flip bit 5 and you swap case. 'A' is 0100 0001 and 'a' is 0110 0001; the only difference is that one lit bit.'A'
= 65
= 0x41, 'a'
= 97
= 0x61, 0x61 - 0x41
= 0x20
= 32
= bit 5 (uppercase + 0x20 = lowercase)
The digit characters have their own shortcut. Since
'0' is code 48 (0x30), the character '7' is code 55, and 55 - 48 = 7 recovers the actual number the character shows. **Subtracting 0x30 turns a digit character into its numeric value**, which is exactly what a program does when it reads a typed number one character at a time.'0'
= 48
= 0x30, '7'
= 55
= 0x37, '7' - '0'
= 55 - 48
= 7 (digit character minus 0x30 = its value)
Worked example: encoding a word
Encode the word
Hi into bytes. Look up each character's code, then write it in hex and binary:His the 8th uppercase letter, so its code is65 + 7 = 72, which is0x48, or0100 1000as a byte.iis the 9th lowercase letter, so its code is97 + 8 = 105, which is0x69, or0110 1001as a byte.- So
Hiis the two-byte sequence72 105, written0x48 0x69, or the bits0100 1000 0110 1001.
ASCII is why text can travel through hardware that only understands numbers. A key press, a byte in RAM, a character on a bus, and a pixel-drawn glyph are all tied together by the code table: the keyboard sends
65, memory stores 65, and the display font draws the shape for 65. It also shows the payoff of a well-designed encoding: laying the ranges out in order turns case conversion and digit reading into one subtraction instead of a lookup table.The byte figure below lets you dial in any 8-bit code by hand. Set bit
b6 and bit b0 (the pattern 0100 0001, which is 0x41) to spell the code for A; flip bit b5 on as well (0110 0001, 0x61) to turn it into a.b7-b0 and read them back on the probes. Dial 0100 0001 (0x41) for A, then turn on b5 (the 0x20 case bit) to get 0110 0001 (0x61), the code for a. Open it in the lab and try a few characters from the table.Common mistakes. The character
'7' (code 55) is not the number 7; to get the value you subtract '0' (48), and forgetting that is a classic bug when parsing typed digits. Do not assume one byte is always one character either: that is only true for plain ASCII. And remember ASCII is a 7-bit code (0 to 127); the top bit of the byte is spare, and different systems have used it for different "extended" characters, which is one reason a single agreed 8-bit character set never really existed. Finally, control codes like NUL (0) and newline (10) are real characters in the stream even though they print nothing.Modern text uses UTF-8, a variable-length encoding whose one-byte codes are exactly ASCII (
0 to 127), so every ASCII file is already valid UTF-8, while characters beyond ASCII (accented letters, other scripts, emoji) use two to four bytes each. ASCII is the foundation UTF-8 was built to extend.Try it
The character
'B' has ASCII code 66. Using the case bit, what is the code for 'b'? And using the digit trick, what value does the digit character '9' (code 57) represent?Answer
Add the case bit
0x20 (32): 66 + 32 = 98, so 'b' is code 98 (0x62), one above 'a' (97), as expected. For the digit, subtract '0' (48): 57 - 48 = 9, so the character '9' stands for the value 9. The tidy ASCII ranges make both conversions a single addition or subtraction.You now know how text becomes bits: pick a code table, and every character is just a number your circuits can store and move. Next in the number track are codes built to *survive* mistakes, error detection and correction, and the arithmetic tracks put these numbers to work: adding, subtracting, and multiplying them in hardware.
Frequently asked
What is ASCII?
ASCII (American Standard Code for Information Interchange) is a character encoding that assigns every letter, digit, punctuation mark, and control code a 7-bit number from
0 to 127. Text is stored as a sequence of these codes, for example A is 65 (0x41) and a is 97 (0x61). It is usually stored one character per byte, with the byte's top bit 0.What is the ASCII code for 'A'?
The ASCII code for
A is 65, written 0x41 in hex or 0100 0001 in binary. Uppercase letters run from A = 65 to Z = 90. The lowercase a is 97 (0x61), exactly 32 more, because uppercase and lowercase differ by the single bit worth 0x20.How do you convert a character to a number in ASCII?
Look the character up in the ASCII table to get its code. For digit characters there is a shortcut: subtract the code of
'0' (48, or 0x30). For example '7' is code 55, and 55 - 48 = 7, so subtracting 0x30 turns the digit character into the value it shows. To swap a letter's case, flip the bit worth 0x20 (32): uppercase plus 0x20 gives lowercase.What is the difference between ASCII and Unicode (UTF-8)?
ASCII is a 7-bit code with only 128 characters, enough for English letters, digits, and punctuation. Unicode assigns a number to essentially every character in every writing system, and UTF-8 is the common way to store those numbers using one to four bytes each. UTF-8's one-byte codes are exactly ASCII (
0 to 127), so ASCII text is already valid UTF-8, but characters beyond ASCII need more than one byte.Every lesson here builds toward one thing: a working CPU, from the transistor up.
Open the free lab →