On this page

History · Control codes

ASCII control characters

Thirty-three codes built to drive teletypes, and the handful that still run your terminal.

Open an ASCII table and the first two columns hold abbreviations instead of characters: NUL, SOH, BEL, ESC. These are the control characters, the 32 codes from 0 to 31 plus DEL at 127. None of them prints anything. They were designed to make a machine do something: ring a bell, move the paper, start a tape reader, or mark where a message begins and ends.

Most were built for teleprinters and data links that are long gone. A few still do the job they were designed for, and several others have been given new ones.

On a keyboard you reach them with Ctrl: Ctrl-G sends BEL, and Ctrl-M sends CR. Why Ctrl works that way is a story of its own.

Hex Code Built to Today
00 NUL Fill time or blank tape In use: ends C strings
01 SOH Start a message heading Rare
02 STX Start the message text Rare
03 ETX End the text Repurposed: Ctrl-C interrupts
04 EOT End the transmission Repurposed: Ctrl-D ends input
05 ENQ Ask the far end to identify itself Rare
06 ACK Confirm receipt Rare
07 BEL Ring a bell In use: terminal bell
08 BS Move back one space In use
09 HT Jump to the next tab stop In use
0A LF Advance one line In use
0B VT Jump to a preset line Rare
0C FF Start a new page Rare
0D CR Return to the start of the line In use
0E SO Switch to another character set Rare
0F SI Switch back Rare
10 DLE Change the meaning of what follows, for link control Rare
11 DC1 Switch a device on Repurposed: XON, Ctrl-Q
12 DC2 Control a device Rare
13 DC3 Switch a device off Repurposed: XOFF, Ctrl-S
14 DC4 Stop a device Rare
15 NAK Reject what was received Repurposed: Ctrl-U erases the line
16 SYN Keep a synchronous link in step Rare
17 ETB End a block of data Rare
18 CAN Disregard the data sent with it Rare
19 EM Mark the end of the tape Rare
1A SUB Stand in for a garbled character Repurposed: Ctrl-Z suspends
1B ESC Change the meaning of what follows In use: terminal sequences
1C FS Separate files Repurposed: Ctrl-\ quits
1D GS Separate groups Rare
1E RS Separate records Rare: JSON text sequences
1F US Separate units Rare
7F DEL Erase a character on tape In use
Table 1 The 33 control codes, what they were built to do, and where they stand today.

Running the line

The largest group managed traffic between machines. A message could open with SOH (start of heading) and some routing information, move on to its body with STX (start of text), and close with ETX (end of text). EOT (end of transmission) said the sender was finished.

The receiving station replied with ACK (acknowledge) or NAK (negative acknowledge). On synchronous links, where both ends kept time with each other, SYN filled idle moments to hold them in step. DLE (data link escape) gave the next few characters a special meaning for controlling the link.

ENQ (enquiry) asked the far end to identify itself. Its 1963 name, WRU, put it more plainly: who are you? A Teletype Model 33 answered with a small drum of breakable tabs, coded with the station’s identity, which turned and sent that identity back down the line.

Few of these codes are seen today. One survivor: xterm still answers ENQ, though by default its answer is empty.

Moving the paper

The format effectors controlled layout on a printing terminal. BS (backspace) moved the print head back one position, so a typist could strike over a character, for example to underline it. HT (horizontal tab) jumped to the next tab stop, as on a typewriter. VT (vertical tab) moved down to a preset line, and FF (form feed) advanced to the top of the next page. CR and LF split a new line into two motions, returning the carriage and advancing the paper, a split that still causes trouble.

This group survived best. Tab, line feed and carriage return appear in nearly every text file, and XML 1.0 allows those three and bans every other code below 0x20.

Vertical tab and form feed are mostly a legacy: xterm, for one, treats both as an ordinary line feed.

Bells and switches

BEL did what its name says. On a Teletype it rang a real bell, so a distant sender could call an operator over to the machine. DC1 to DC4 (device controls) were left general: the standard says only that they switch auxiliary devices on or off, with DC4 the preferred way to stop one. The Teletype Model 33 used DC1 and DC3 to switch an attached device, such as its paper-tape punch, on and off, and those two codes came to be known as XON and XOFF.

Both ideas lasted. Terminals still sound a bell when they receive BEL, and xterm also accepts it as the end of certain escape sequences. XON and XOFF became flow control: a device sends DC3 to say “stop sending” and DC1 to say “carry on.” That’s why Ctrl-S freezes the output in many Unix terminals, and Ctrl-Q brings it back.

Files, groups, records, units

Four codes, FS, GS, RS and US (file, group, record and unit separator), were meant to divide data into nested levels, from the largest to the smallest. In the 1963 chart they were unnamed separators, S4 to S7.

They make ideal delimiters, because they never appear in ordinary text. In practice the comma and the tab won, and CSV has to quote any field that contains a comma. Unicode still gives them separator roles in bidirectional text, where FS, GS and RS end a paragraph and US ends a segment. RS has also found a modern job: RFC 7464 uses it to mark the start of each record in a stream of JSON texts. JSON doesn’t allow a raw control character, so an RS can only mean that a new record begins.

Shifting and escaping

SO (shift out) and SI (shift in) switched to another character set and back, much as telegraph codes had shifted between letters and figures. The pair was still being specified in the 1990s: ISO-2022-KR, a Korean email encoding defined in 1993, used SO to switch from ASCII into Korean characters and SI to switch back.

ESC did the same job more broadly. It changes the meaning of the characters that follow it, which is how terminals still receive colours and cursor movements.

Filler, mistakes and endings

NUL is the all-zero code. On paper tape, blank leader with no holes read as NUL, and the standard used it as filler to pass time or fill space. Today it marks the end of a string in C.

CAN (cancel) told the receiver to disregard data just sent. EM (end of medium) marked the physical end of a tape, or the end of its used part. SUB (substitute) stood in for a character that had arrived garbled.

SUB found a second career. CP/M recorded file sizes only in 128-byte blocks, so a text file could end partway through its last block, followed by leftover bytes. Programs marked the real end with Ctrl-Z, which sends SUB. DOS kept the habit, and the Windows copy command still stops at the first Ctrl-Z when it’s told a file is text.

DEL, the code with every hole punched, has its own article.

The ones you still press

Several codes now do jobs ASCII never gave them. On Linux, the terminal driver watches for certain control characters as you type and acts on them itself:

  • Ctrl-C sends ETX (end of text) and interrupts the running program.
  • Ctrl-D sends EOT (end of transmission) and signals the end of input.
  • Ctrl-Z sends SUB and suspends the program.
  • Ctrl-U sends NAK and erases the line you’re typing.
  • Ctrl-\ sends FS and quits the program.

Some of the new meanings echo the old names: end of text, end of transmission. Others have nothing to do with them. Either way, the meaning now comes from the terminal, not from ASCII.

Read down the table’s last column and the pattern is clear. Most of the codes that laid out a page, such as tab, line feed and carriage return, are still everywhere. The ones that ran a link or a tape punch either retired or found work under a new name.

Continue reading

Sources

  1. American Standards Association, American Standard Code for Information Interchange, X3.4-1963, p. 5 (the 1963 code chart). — and Vint Cerf, “ASCII format for Network Interchange,” RFC 20, October 1969, which reproduces the control definitions of USAS X3.4-1968. https://www.rfc-editor.org/rfc/rfc20
  2. Tom Jennings, “An annotated history of some character codes,” including the sections ASCII-1963 and ASCII-1967. https://www.sr-ix.com/Archive/CharCodeHist/index.html
  3. Linux man-pages, “termios(3).” https://man7.org/linux/man-pages/man3/termios.3.html — The Open Group, POSIX.1-2024, Chapter 11 “General Terminal Interface.” https://pubs.opengroup.org/onlinepubs/9799919799/basedefs/V1_chap11.html — and Thomas E. Dickey, “XTerm Control Sequences.” https://invisible-island.net/xterm/ctlseqs/ctlseqs.html
  4. The Unicode Consortium, The Unicode Standard, Version 18.0, §23.1 “Control Codes.” https://www.unicode.org/versions/Unicode18.0.0/core-spec/chapter-23/ — and W3C, Extensible Markup Language (XML) 1.0 (Fifth Edition), §2.2 “Characters” and §4.1 “Character and Entity References.” https://www.w3.org/TR/xml/
  5. N. Williams, “JavaScript Object Notation (JSON) Text Sequences,” RFC 7464, February 2015. https://www.rfc-editor.org/rfc/rfc7464 — and U. Choi, K. Chon and H. Park, “Korean Character Encoding for Internet Messages,” RFC 1557, December 1993. https://www.rfc-editor.org/rfc/rfc1557
  6. Michal Necasek, “Misconceptions on Top of Misconceptions,” OS/2 Museum. https://www.os2museum.com/wp/misconceptions-on-top-of-misconceptions/ — and Microsoft, “copy,” Windows Commands. https://learn.microsoft.com/en-us/windows-server/administration/windows-commands/copy