Escape Sequences
Backslash-prefixed sequences in string and character literals that represent otherwise unrepresentable or syntactically ambiguous characters.
Escape Sequencessince C++98An escape sequence is a backslash followed by one or more characters within a string or character literal that the compiler translates β at compile time β into a single character value that would otherwise be syntactically reserved, non-printable, or platform-specific.
Overview
Escape sequences are resolved during translation phase 5, before any runtime execution. They appear in character literals ('\n'), narrow string literals ("\n"), and their prefixed variants (u8"\n", u"\n", U"\n", L"\n"). There are three categories: simple sequences with fixed semantics, numeric sequences specifying code points directly, and universal character names for Unicode portability.
Simple Escape Sequences
| Sequence | Meaning | ASCII |
|---|---|---|
\\ | backslash | 0x5C |
\' | single quote | 0x27 |
\" | double quote | 0x22 |
\? | question mark | 0x3F |
\a | audible bell | 0x07 |
\b | backspace | 0x08 |
\f | form feed | 0x0C |
\n | line feed (newline) | 0x0A |
\r | carriage return | 0x0D |
\t | horizontal tab | 0x09 |
\v | vertical tab | 0x0B |
\? exists to prevent trigraph interpretation (e.g., ??= would otherwise be tokenised as #). Trigraphs were deprecated in C++14 and removed in C++17, so \? has no relevance in modern code targeting C++17 or later.
The null character (\0) is technically the octal escape sequence with value zero, not a simple escape sequence, but it is universally treated as a named constant.
Numeric Escape Sequences
Octal
char bell = '\a'; // simple escape
char bell2 = '\007'; // same value via octal β 1 to 3 digits, each 0β7
char A = '\101'; // octal 101 = decimal 65 = 'A'Exactly 1β3 octal digits are consumed. The digit 8 and 9 are not octal digits; '\8' and '\9' are ill-formed.
char bad = '\9'; // ill-formed
char ok = '\07'; // BEL, same as '\a'Hexadecimal
char A = '\x41'; // 'A'
char nul = '\x00'; // null character
char bel = '\x07'; // audible bellUnlike octal, the hex form is greedy: it consumes all subsequent hexadecimal characters. When the character immediately after the escape is a hex digit, split the literal explicitly:
const char* wrong = "\xabcdef"; // one character with value 0xABCDEF β likely UB or truncation
const char* ok = "\xab" "cdef"; // 0xAB then the string "cdef"
const char* also = "\x0a" "Blue"; // '\n' then "Blue" β 'B' is hex so split is mandatoryC++23: Delimited Numeric Escapes
C++23 (P2290R3) introduces brace-delimited forms that solve the greedy problem and reject out-of-range values at compile time:
// C++23
char c = '\o{101}'; // octal β equivalent to '\101'
char d = '\x{41}'; // hex β equivalent to '\x41'
const char* s = "\x{0a}face"; // unambiguous newline then "face"
char16_t bad = u'\x{FFFFFF}'; // ill-formed: value exceeds char16_t rangeUniversal Character Names
Universal character names (UCNs) specify Unicode code points in any string or character literal. The encoding used depends on the literal prefix.
// Available since C++98
char32_t euro = U'\u20AC'; // U+20AC EURO SIGN β 4 hex digits, BMP only
char32_t snowman = U'\U00002603'; // U+2603 SNOWMAN β 8 hex digits, full Unicode range
const char* utf8_euro = u8"\u20AC"; // encodes U+20AC as UTF-8: 0xE2 0x82 0xAC
wchar_t wide_euro = L'\u20AC'; // platform-dependent encoding\uNNNN requires exactly 4 hex digits. \UNNNNNNNN requires exactly 8. Both work in char, char8_t, char16_t, char32_t, and wchar_t contexts; the compiler encodes the code point appropriately for the target type.
C++23: Named Character Escapes
C++23 (P2071R2) introduces \N{name} using the official Unicode character database name:
// C++23
char32_t snowman = U'\N{SNOWMAN}'; // U+2603
char32_t smiley = U'\N{GRINNING FACE}'; // U+1F600
const char* euro = u8"\N{EURO SIGN}"; // UTF-8 encoded β¬Names must exactly match the Unicode character database. This is strictly a compile-time feature. Prefer it over raw code points in any context where readability matters.
C++23: Delimited Universal Character Escape
// C++23
char32_t emoji = U'\u{1F600}'; // avoids the 8-digit \U form for code points above U+FFFFRaw String Literals (C++11)
When expressions contain many escape sequences, raw string literals eliminate them entirely:
// C++11
const char* path_esc = "C:\\Users\\alice\\Documents\\notes.txt";
const char* path_raw = R"(C:\Users\alice\Documents\notes.txt)";
const char* json_esc = "{\"key\": \"value\", \"n\": 42}";
const char* json_raw = R"({"key": "value", "n": 42})";
const char* re_esc = "(\\w+)\\s+(\\d{1,3}\\.\\d{1,3})";
const char* re_raw = R"((\w+)\s+(\d{1,3}\.\d{1,3}))";The syntax is R"delimiter(content)delimiter" where delimiter is any string of up to 16 characters (excluding space, \, (, )). Use a custom delimiter when the content contains )":
const char* tricky = R"delim(ends with )" here)delim"; // C++11Best Practices
Prefer '\n' over std::endl in output loops. std::endl flushes the stream buffer; '\n' does not. Flushing on every line is expensive when writing large amounts of output.
for (const auto& line : lines) {
std::cout << line << '\n'; // fast
// std::cout << line << std::endl; // flushes each iteration β avoid
}Use raw string literals for paths and regular expressions. Double-escaping is error-prone and obscures intent.
Split hex escapes explicitly when the next character is alphanumeric:
const char* ambiguous = "\x0dA"; // is this 0x0DA or CR + 'A'? β formally CR + 'A', but misleading
const char* clear = "\x0d" "A"; // unambiguous: CR then 'A'Common Pitfalls
Windows file paths. The most common production mistake involving escape sequences:
const char* broken = "C:\new_folder\test.txt"; // \n and \t are escapes β BUG
const char* fixed = "C:\\new_folder\\test.txt";
const char* clean = R"(C:\new_folder\test.txt)"; // C++11 β preferredNull bytes in std::string. std::string can contain embedded null bytes, but the single-argument string literal constructor stops at the first null from strlen's perspective:
std::string s = "abc\0def"; // .size() == 3 β "def" is silently dropped
std::string t("abc\0def", 7); // .size() == 7 β explicit length constructor
std::string u = "abc"s; // using namespace std::string_literals (C++14)Octal range errors. Digits 8 and 9 are not octal; combining them with \ is ill-formed:
char c = '\8'; // ill-formed
char d = '\08'; // ill-formed β 0 is valid octal but 8 is not
char e = '\07'; // fine β BEL characterGreedy hex in concatenated literals. Adjacent string literals are each processed independently, so cross-literal hex ambiguity does not occur β but ambiguity within a single literal's fragment still does:
const char* ok = "\x61" "b"; // 'a' + 'b' β unambiguous
const char* trap = "\x61b"; // 0x61B, not 'a' + 'b' β single literal, greedy\r\n vs \n in binary I/O. Text-mode streams on Windows translate \n to \r\n on write. When working with network protocols, binary file formats, or cross-platform data, open streams in binary mode and write \r\n explicitly rather than relying on platform translation.
// For CRLF-terminated HTTP headers:
std::string header = "HTTP/1.1 200 OK\r\n"
"Content-Type: text/plain\r\n"
"\r\n";Universal Character Names in Depth
Universal character names (UCNs) have been part of C++ since C++98 and are the canonical mechanism for embedding arbitrary Unicode code points in source code in a portable, encoding-independent way.
Two Forms
\uNNNN uses exactly 4 hex digits and can express any code point in the Basic
Multilingual Plane (U+0000 through U+FFFF).
\UNNNNNNNN uses exactly 8 hex digits and can express any code point in the
full Unicode range up to U+10FFFF.
// \uNNNN β BMP only (U+0000βU+FFFF)
const char32_t degree = U'Β°'; // U+00B0 DEGREE SIGN Β°
const char32_t euro = U'β¬'; // U+20AC EURO SIGN β¬
const char32_t chess = U'β'; // U+265E BLACK CHESS KNIGHT β
// \UNNNNNNNN β full Unicode range including supplementary planes
const char32_t snowman = U'\U00002603'; // U+2603 SNOWMAN β
const char32_t emoji = U'\U0001F600'; // U+1F600 GRINNING FACE π
const char32_t musical = U'\U0001D11E'; // U+1D11E MUSICAL SYMBOL G CLEF πThe encoding produced in the resulting literal depends on the prefix. In a u8
literal the compiler encodes the code point as UTF-8; in a u literal as
UTF-16; in a U literal as UTF-32; in an L literal as the platform's wide
character encoding; in an unadorned char literal as the execution character
set (usually UTF-8 on modern targets).
// Same code point, four encodings
const char* utf8 = "β¬"; // 3 bytes: 0xE2 0x82 0xAC
const char8_t* u8s = u8"β¬"; // same bytes, type is const char8_t*
const char16_t* u16 = u"β¬"; // 1 char16_t: 0x20AC
const char32_t* u32 = U"β¬"; // 1 char32_t: 0x000020AC
const wchar_t* wide = L"β¬"; // platform-dependentUCNs in Identifiers
UCNs are permitted in identifiers, which allows non-ASCII names written in portable source form:
int Ξ± = 1; // variable named Ξ± (U+03B1 GREEK SMALL LETTER ALPHA)
int cafΓ© = 2; // cafΓ©However, the standard forbids using a UCN in an identifier if the code point it denotes falls in the range U+0000βU+001F (C0 control characters), U+007F (DELETE), or U+0080βU+009F (C1 control characters). These ranges are unconditionally excluded from being representable via UCN in identifier positions regardless of compiler extension.
Code points whose UCN encodes a character with XID_Start or XID_Continue property (per Unicode) are valid. Compilers vary in exactly which supplementary plane characters they accept in identifiers, but all mainstream compilers (GCC 10+, Clang 9+, MSVC 19.29+) accept common scripts such as Greek, Arabic, CJK Unified Ideographs, and Cyrillic.
Avoiding Surrogate Pairs
Code points in the range U+D800βU+DFFF are UTF-16 surrogate halves. They are not valid Unicode scalar values and must not appear as UCNs:
char32_t bad = U'\uD800'; // ill-formed β surrogate half is not a scalar valueRaw String Literals
Raw string literals, introduced in C++11, suppress all escape processing inside the string body. The compiler treats every byte between the delimiters as a literal character, including backslashes and newlines.
Syntax
R"delimiter(content)delimiter"delimiter is an optional sequence of up to 16 characters from the set
[A-Za-z0-9_{}#<>%:;.?*+/^&|~!=,\-] β notably excluding space, (, ), and
\. The opening sequence R"delimiter( is terminated only by the matching
closing sequence )delimiter".
// C++11
const char* path = R"(C:\Users\alice\Documents\notes.txt)";
const char* json = R"({"key": "value", "flag": true})";
const char* re = R"((\d{1,3}\.){3}\d{1,3})"; // IP address regexMultiline Raw Strings
Because newlines are not escaped, a raw string can span multiple lines exactly as written in the source file. The literal value includes the newlines:
const char* html = R"(<!DOCTYPE html>
<html>
<body>
<p>Hello, world.</p>
</body>
</html>
)";
// html[0] == '<', and the string ends with '\n' before the closing )".This is especially useful for embedding SQL, GLSL shaders, JSON schemas, or any other block text where line structure is meaningful.
Custom Delimiters for Content Containing )
If the string content must contain the sequence )", choose any delimiter that
does not appear in the content as )delimiter":
const char* html_attr = R"html(onclick="doSomething()")html";
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^
// content contains )" β safe because delimiter is "html"
const char* nested = R"---(text with )" and )--" inside)---";The choice of delimiter name is arbitrary. Common conventions are short
identifiers like raw, lit, str, or project-specific tags.
Unicode-Prefixed Raw String Literals
All encoding prefixes can be combined with R:
// C++11
const char8_t* u8r = u8R"(UTF-8 raw: no \n processing here)";
const char16_t* u16r = uR"(UTF-16 raw literal)";
const char32_t* u32r = UR"(UTF-32 raw literal)";
const wchar_t* wr = LR"(wide raw literal)";The prefix controls the encoding of the resulting string, not how the source bytes are scanned. Escape sequences are still suppressed; only encoding of the literal bytes into the target type differs.
Raw Strings and constexpr
Raw string literals are fully usable in constexpr and consteval contexts:
constexpr const char* pattern = R"(\b\w+\b)"; // C++11 constexpr raw stringC++23 New Escape Sequences
C++23 standardised several additions that were either extensions or entirely new mechanisms. All require a conforming C++23 compiler; GCC 13+, Clang 16+, and MSVC 19.36+ have varying degrees of support.
\N{name} β Named Character Escapes (P2071R2)
The \N{name} form lets you write a character by its official Unicode character
database name. The name is looked up at compile time; an unrecognised name is a
hard error.
// C++23
char32_t snowman = U'\N{SNOWMAN}'; // U+2603
char32_t em_dash = U'\N{EM DASH}'; // U+2014
char32_t copyright = U'\N{COPYRIGHT SIGN}'; // U+00A9
char32_t grinning = U'\N{GRINNING FACE}'; // U+1F600
const char* greeting = u8"\N{LATIN SMALL LETTER A}\N{LATIN SMALL LETTER B}";
// identical to u8"ab", but names make intent explicit in generated-code contextsNames must match Unicode exactly, including spaces and capitalisation. Common names to know:
| Name | Code Point | Glyph |
|---|---|---|
LATIN SMALL LETTER A | U+0061 | a |
DIGIT ZERO | U+0030 | 0 |
SNOWMAN | U+2603 | β |
EM DASH | U+2014 | β |
EURO SIGN | U+20AC | β¬ |
GRINNING FACE | U+1F600 | π |
ZERO WIDTH NO-BREAK SPACE | U+FEFF | (BOM) |
\N{name} is not permitted in raw string literals β nothing is: raw strings
suppress all escape processing.
Compiler support as of mid-2026: GCC 13 (full), Clang 17 (full), MSVC 19.36 (partial). Check your project's minimum supported compiler before relying on this in production headers.
\e β The Escape Character (P2290R3)
GCC and Clang have long supported \e as a non-standard extension for the
ESC character (U+001B, decimal 27, octal \033, hex \x1B). C++23 standardises
it:
// C++23 β previously a GCC/Clang extension
const char* reset = "\e[0m"; // ANSI SGR reset
const char* bold = "\e[1m"; // ANSI SGR bold
const char* red = "\e[31m"; // ANSI SGR red foreground
// Equivalent pre-C++23 forms:
const char* reset_old = "\x1B[0m"; // hex β always worked
const char* reset_oct = "\033[0m"; // octal β always worked
const char* reset_ucn = "[0m"; // UCN β always worked\e is strictly syntactic sugar for \x1B; there is no runtime difference.
Its primary value is readability: the intent β "this is an ANSI terminal escape
sequence" β is immediately visible without mental arithmetic.
Delimited Escape Sequences (P2290R3)
C++23 also formalises brace-delimited variants of octal, hex, and universal character name escapes. These are covered in the Numeric Escape Sequences section above, but the rationale deserves emphasis here: they eliminate two long-standing footguns.
The greedy hex problem: "\x0dBlue" is not CR + "Blue" β it is a single
character with code point 0x0DB because B, l, u, e are not hex but B
is. Wait: l, u, e are not hex; B is. So \x0dB (0xDB) followed by
"lue". C++23 "\x{0d}Blue" is unambiguous.
The octal-digit-count problem: '\012' is newline but '\0129' is '\012'
followed by '9' as a multi-character literal (or ill-formed depending on context).
'\o{12}' accepts any number of octal digits inside the braces.
// C++23 delimited forms
char lf = '\o{12}'; // octal newline, unambiguous
char esc = '\x{1B}'; // ESC, no greediness concern
char u = '\u{263}'; // U+0263 LATIN SMALL LETTER GAMMA (variable digit count)
char32_t face = U'\u{1F600}'; // supplementary plane without 8-digit \U formString Literal Concatenation and Encoding
Adjacent string literal tokens are concatenated by the compiler during translation phase 6, after escape sequence resolution. This affects how encodings interact.
Basic Concatenation
// These are all identical
const char* a = "hello " "world";
const char* b = "hello " R"(world)"; // raw + ordinary β same result
const char* c = "hel" "lo " "world"; // three tokensMixing Prefixes
The C++11 rules for concatenating literals with different prefixes:
- If one operand is an unsuffixed (ordinary) string literal and the other is prefixed, the result has the prefixed encoding.
- If both are prefixed, they must have the same prefix (otherwise the program is ill-formed).
- Mixing
u8withuorUis ill-formed.
// Legal: one operand is unsuffixed
const char16_t* p = u"hello " "world"; // result is u"hello world"
const char32_t* q = U"prefix: " "value"; // result is U"prefix: value"
const wchar_t* r = L"path: " R"(\foo)"; // L"path: " + raw β L"path: \\foo" equivalent
// Ill-formed: both prefixed but different
// const char* bad = u8"a" u"b"; // error: u8 + u
// const char* bad = u"a" U"b"; // error: u + Uchar8_t Concatenation (C++20)
C++20 changed u8 string literals to produce const char8_t* rather than
const char*. This affects concatenation: you cannot concatenate a u8 literal
with an unsuffixed char literal and assign to const char*.
// C++20
const char8_t* s = u8"hello " u8"world"; // fine
// const char* t = u8"hello " "world"; // may warn or error: char8_t* vs char*If you need to mix u8 content with byte strings in C++20, cast explicitly or
use std::bit_cast / reinterpret_cast with care.
Concatenation Across Translation Units
String literal concatenation is a compile-time lexical operation β it cannot
span translation units. Literals in separate .cpp files are never
automatically concatenated; that is a link-time operation using arrays or
extern variables.
Using String Literal Suffix s (C++14)
The std::string_literals::operator""s suffix produces a std::string and
is aware of embedded null bytes:
using namespace std::string_literals;
std::string a = "hello\0world"s; // length 11, embedded null preserved
std::string b = u8"cafΓ©"s; // std::string from u8 literal (C++14/17)
// std::u8string c = u8"cafΓ©"s; // std::u8string from u8 literal (C++20)The s suffix does not affect escape-sequence resolution; it merely controls
the type of the resulting object.
See Also
- String literal prefixes:
u8,u,U,Land thessuffix (C++14) char8_t(C++20),char16_tandchar32_t(C++11) β Unicode character types- Raw string literals (C++11):
R"(...)" std::string_literalsandoperator""s(C++14)