Need Help or More Information?
Questions about this free C programming course, embedded C training or career guidance? Get in touch.
C Escape Sequences Tutorial
Control line breaks, tabs, carriage returns and special characters in printf output, with real byte-level proof from four runnable programs. Part of our free embedded C series.
The text you pass to printf is not only letters and format specifiers. It can also contain tiny backslash codes that tell the output device to start a new line, jump to the next tab stop, ring a bell or print a character that would otherwise break your string. These are C escape sequences, and they are the reason your logs look tidy instead of being one long smear of text. This lecture of our free embedded systems course explains each one, shows what bytes are really sent, and explains why serial terminals in embedded projects need a slightly different line ending than your laptop does.
It continues from the printf lecture, so if you have not read it, take five minutes to skim it first. Everything here is also useful groundwork for the free linux device drivers course, where every printk message you write is a string with a trailing newline.
What You Will Learn
After this lecture you will be able to:
- Explain what an escape sequence is and when the compiler converts it.
- Use
\n,\t,\b,\r,\a,\vand\fand predict what appears on screen. - Print quotes, apostrophes and backslashes inside strings.
- Write characters by their hexadecimal or octal code.
- Prove what a program really outputs using
od -candcat -v. - Choose between
\nand\r\nfor embedded serial output.
Prerequisites
- The previous lecture on printf and format specifiers.
- Basic knowledge of the
chartype and string literals. - A Linux shell with
gcc,od,catandexpand(all standard on Ubuntu).
What Are C Escape Sequences?
Inside a string or character literal, a backslash is a signal to the compiler: “the next character is special, treat the pair as one character”. So \n is written with two keystrokes in your source file but becomes a single byte in your program. For the newline that byte has the value 10.
This conversion happens when the compiler reads your source code, before printf ever runs. printf just receives a string that already contains the real control byte. That is different from format specifiers such as %d, which are interpreted by printf at run time. Keeping this split in mind clears up a lot of confusion: backslashes are for the compiler, percent signs are for printf.
| Sequence | Name | Byte value | Effect on a terminal |
|---|---|---|---|
\n | Newline (line feed) | 10 | Moves to the next line |
\t | Horizontal tab | 9 | Jumps to the next tab stop |
\b | Backspace | 8 | Moves the cursor one place left |
\r | Carriage return | 13 | Moves the cursor to the start of the line |
\a | Alert | 7 | Beep, if the terminal allows it |
\v | Vertical tab | 11 | Terminal dependent, often just moves down |
\f | Form feed | 12 | Terminal dependent, meaningful mainly to printers |
\\ | Backslash | 92 | Prints one backslash |
\" | Double quote | 34 | Prints a double quote inside a string |
\' | Single quote | 39 | Prints an apostrophe or quote character |
\0 | Null character | 0 | Ends a C string |
Newline and Tab: The C Escape Sequences You Use Daily
The Newline Character
Without \n, printf keeps writing on the same line, and the shell prompt ends up glued to your last word. Almost every log line you ever print should end with a newline. A bonus: when stdout is a terminal, the newline also causes buffered text to be flushed, so your message appears immediately.
The Tab Character and Tab Stops
A tab does not insert a fixed number of spaces. It moves to the next tab stop, and by default terminals place a stop every eight columns. That is why tabs make quick, aligned tables. Save this as ep_tab_table.c:
#include <stdio.h>
int main(void)
{
printf("Pin\tMode\tState\n");
printf("PA5\tOutput\tHigh\n");
printf("PC13\tInput\tLow\n");
return 0;
}
gcc -Wall -Wextra -std=c11 -o ep_tab_table ep_tab_table.c
./ep_tab_table
Expected output (tab stops every 8 columns):
Pin Mode State
PA5 Output High
PC13 Input Low
To see that a tab is a single byte and not spaces, pipe the output through od -c, which prints each byte by name:
./ep_tab_table | od -c | head -3
0000000 P i n \t M o d e \t S t a t e \n P
0000020 A 5 \t O u t p u t \t H i g h \n P
0000040 C 1 3 \t I n p u t \t L o w \n
Watch out: tab width is a display setting, not a property of your program. The same output can look different in another editor or terminal. For tables that must align everywhere, use printf width specifiers such as %-8s instead of tabs.
Cursor Control With C Escape Sequences
The next group of C escape sequences moves the cursor instead of printing something visible. These are the ones that surprise students, because the final screen shows less than what was sent. Save this as ep_cursor_moves.c:
#include <stdio.h>
int main(void)
{
printf("ABC\b\bX\n");
printf("Loading...\rDone! \n");
printf("OK\r\n");
return 0;
}
gcc -Wall -Wextra -std=c11 -o ep_cursor_moves ep_cursor_moves.c
./ep_cursor_moves | cat -v
The cat -v command makes control characters visible, which is the honest view of what the program wrote:
ABC^H^HX
Loading...^MDone!
OK^M
Here ^H is backspace and ^M is carriage return. If you run the program directly in a terminal instead, you see the effect of those controls:
AXC
Done!
OK
Carriage Return for Progress Messages
The carriage return puts the cursor back at column 0 without going down a line, so the next text overwrites the old. That is the trick behind single-line progress indicators. In our sample, Loading... is overwritten by Done!, and the trailing spaces are needed to wipe the leftover dots because the new text is shorter than the old.
Alert, Vertical Tab and Form Feed
Let us look at the remaining three with a short program, ep_beep.c:
#include <stdio.h>
int main(void)
{
printf("Alert!\a\n");
printf("Col1\vCol2\fCol3\n");
return 0;
}
gcc -Wall -Wextra -std=c11 -o ep_beep ep_beep.c
./ep_beep | od -c
0000000 A l e r t ! \a \n C o l 1 \v C o l
0000020 2 \f C o l 3 \n
0000027
The bytes are exactly what you wrote: 7 for the alert, 11 for the vertical tab and 12 for the form feed. What they do depends entirely on the receiving device. Many terminal emulators mute the bell. A vertical tab and form feed were designed for printers, and on a typical modern terminal they only move the cursor down without returning to the left edge, which makes the next text appear to step to the right. Treat them as rarely useful in everyday code.
Printing Quotes and Backslashes With Escape Sequences
A double quote ends a string literal, and a backslash starts an escape. So how do you print either one? You escape them. Save this as ep_quotes.c:
#include <stdio.h>
int main(void)
{
printf("Log says: \"Sensor ready\"\n");
printf("Path: C:\\embedded\\logs\n");
printf("Apostrophe: it\'s fine, and so is it's\n");
printf("Chars: %c %c %c\n", '\'', '"', '\\');
printf("Hex escape: \x48\x69\n");
printf("Octal escape: \110\151\n");
return 0;
}
gcc -Wall -Wextra -std=c11 -o ep_quotes ep_quotes.c
./ep_quotes
Expected output:
Log says: "Sensor ready"
Path: C:\embedded\logs
Apostrophe: it's fine, and so is it's
Chars: ' " \
Hex escape: Hi
Octal escape: Hi
A few points are worth noticing. Inside a string you do not have to escape an apostrophe, but it is allowed. Inside a character literal the situation flips: you must write '\'' for the apostrophe, while '"' needs no escape. The last two lines show that any character can be written by its code: \x48\x69 is hexadecimal for H and i, and \110\151 is octal for the same two letters. This is handy for non-printable bytes in protocols, such as writing an ESC character as \x1b.
Predict the Output (Try Before You Click)
Challenge 1
printf("One\nTwo\tThree\n");
Show answer
One
Two Three
The newline splits the text into two lines. On the second line, “Two” takes columns 0 to 2 and the tab moves to column 8.
Challenge 2
printf("12345\rAB\n");
Show answer
AB345
The carriage return returns to column 0, and AB overwrites only the first two characters.
Challenge 3
printf("Say \"%s\" to the \\ team\n", "hi");
Show answer
Say "hi" to the \ team
The escaped quotes and the double backslash become single characters before printf runs.
Challenge 4
printf("AB\0CD\n");
Show answer
AB
The null character ends the string, so printf stops there. The newline never gets printed, so your prompt may appear right after the AB.
Escape Sequences in Embedded Serial Output
Here is something that bites almost every newcomer to microcontrollers. On Linux, a newline moves down a line and returns to the left edge, so \n alone is enough. A raw serial terminal program often does not add that return for you. If your firmware sends only \n, the text can step across the screen like a staircase. The usual fix is to send \r\n, the traditional line ending of serial consoles.
| Environment | Typical line ending | Why |
|---|---|---|
| Linux terminal and files | \n | The terminal driver handles the return for you |
| Raw UART to a serial terminal | \r\n | Terminal may not add a return on its own |
| Windows text files | \r\n | Historical convention |
Linux kernel printk | \n | Terminates the message; do not add \r |
Common C Escape Sequence Mistakes
- Using a forward slash:
"/n"prints a slash and the letter n. The newline needs a backslash. - A single backslash in a path:
"C:\new"contains a newline, not a folder called new. Double every backslash. - Greedy hex escapes:
\xconsumes as many hexadecimal digits as it can, so"\x41B"is one oversized value, not A followed by B. Compilers warn or reject it. Split the string, for example"\x41" "B". - Forgetting the trailing newline: the next program output or shell prompt gets glued onto your last line.
- Expecting \a to beep everywhere: many terminals and all headless systems stay silent.
Best Practices, Performance and Security
Best Practices
- Use
od -corcat -vwhenever output looks wrong. It shows the true bytes. - Prefer
\nin portable code and add\ronly where the target device needs it. - Avoid
\vand\fin normal logging. - Write raw bytes in protocols with explicit hex escapes and add a comment.
Performance Considerations
Escape sequences cost nothing at run time because the compiler resolves them while compiling. The only real cost is the extra byte on the wire. On a slow UART at 9600 baud, the additional \r in every line does add a little transmission time, so keep log lines short.
Security Considerations
Control bytes from C escape sequences in logs can be abused. A user-supplied string containing \r or terminal escape codes can overwrite earlier log text on a screen and hide activity. When you print untrusted input, sanitize or replace non-printable characters, and remember to print it with printf("%s", text) rather than using it as the format string.
Quick Quiz
Question 1
How many bytes does the two-character source text \n become in a string?
Show answer
One byte, with the value 10.
Question 2
Which sequence would you use for a progress line that updates in place?
Show answer
The carriage return, \r, often with trailing spaces to erase leftover text.
Question 3
Your UART logs form a staircase on the PC. What is the likely fix?
Show answer
Send \r\n instead of only \n, or enable newline translation in the terminal program.
Interview Questions on Escape Sequences
- Who processes
\n, the compiler or printf? The compiler converts it into a single byte; printf just passes it along. - What is the difference between
\rand\n? Carriage return goes to the start of the current line; newline moves to the next line. - How do you print a double quote inside a string? Use
\". - What does
\0do inside a string literal? It terminates the string for functions such as printf. - How can you inspect raw output bytes? Pipe the output through
od -corcat -v. - Why can a Windows path in a C string break? Single backslashes start escape sequences, so each must be doubled.
Summary and Key Takeaways
- An escape sequence is a backslash pair that the compiler turns into one special byte.
- Percent signs are handled by printf at run time; backslashes by the compiler at build time.
- Among C escape sequences,
\n,\t,\rand\bare the everyday workhorses. \a,\vand\fsend valid bytes, but the effect depends on the device.- Escape quotes and backslashes with a preceding backslash, and use hex or octal escapes for arbitrary bytes.
- Serial consoles often need
\r\n. od -candcat -vreveal what a program truly printed.
Conclusion
You have now seen that C escape sequences are small but powerful tools: they shape the layout of every message your embedded code or driver prints. Together with format specifiers from the previous lecture, you can build clean, readable output for terminals, serial consoles and kernel logs. This knowledge is a stepping stone in the free embedded linux course and the free linux kernel development course, where well-formed log messages save hours of debugging. Next, we move on to formatted input and output, where you will control field width and alignment. Until then, experiment with the programs above and inspect their bytes with od -c.
Frequently Asked Questions
What is an escape sequence in C?
It is a backslash followed by a character, written inside a string or character literal, that represents a special character such as a newline or tab.
What is the difference between \n and \r?
The newline \n moves to the next line, while the carriage return \r moves back to the beginning of the current line.
How do I print a backslash in C?
Write two backslashes in the string, \\. The compiler turns them into one backslash character.
Why does my serial output look like a staircase?
The terminal received a newline without a carriage return. Send \r\n or configure the terminal to add the return.
Do escape sequences slow down my program?
No. The compiler resolves them at build time. They only add one byte per sequence to the output.
Where can I learn more for free?
EmbeddedPathashala publishes a free embedded systems course, a free linux development course, a free linux device drivers course and a free linux kernel development course for students.
Continue the Free Embedded C Course
Next up: formatted input and output, where you control field width and alignment for neat, professional output.
Need Help or More Information?
Questions about this free C programming course, embedded C training or career guidance? Get in touch.

2 Comments