Question
How can I define a plain-text, constant string literal that spans multiple lines in C++, similar to Perl's multi-line string syntax? Is there a useful preprocessing technique, such as including text from another file? I am aware that C++11 provides raw string literals.
Short Answer
You will learn the two main ways to represent multi-line text in C++: raw string literals in C++11 and later, and adjacent string literal concatenation for older C++ standards. You will also see how line endings, indentation, and preprocessor line continuation affect the resulting string.
Concept
A normal C++ string literal cannot contain a physical newline directly between its opening and closing quotes. This is invalid:
const char* message = "Hello
world"; // Invalid C++
C++ offers two practical approaches:
- Raw string literals preserve most text exactly as written. They are ideal for JSON, SQL, HTML, regular expressions, and multi-line messages.
- Adjacent string literal concatenation lets you split one logical string across several source lines. It works in older C++ versions and gives precise control over where
\ncharacters appear.
This matters because source formatting and string contents are different things. A string may be displayed across several lines in your editor, but it contains newline characters only when you explicitly include them or use a raw string containing actual newlines.
Mental Model
Think of a string literal as a sealed envelope containing characters.
- A normal string literal requires special characters to be written using escape codes, such as
\nfor a new line and\"for a quote. - A raw string literal is like an envelope where you can write the message directly, including quotes, backslashes, and line breaks.
- Adjacent literals are several envelope pieces that the compiler joins into one envelope before the program runs.
The compiler cares about both the characters inside the string and the rules used to write them in C++ source code.
Syntax and Examples
Raw string literals (C++11 and later)
Prefix the opening quote with R:
const char* poem = R"(Roses are red,
Violets are blue,
C++ strings can span lines,
And keep quotes too.)";
The variable contains the newline characters shown between the lines. Backslashes and double quotes do not need escaping inside this raw string.
const char* json = R"({
"name": "Ada",
"active": true
})";
Custom raw-string delimiter
A raw string ends at )" by default. If your text contains that sequence, add a delimiter label after R" and before the final quote:
const char* text = R"TEXT(This text can contain )" safely.)TEXT";
The opening delimiter is R"TEXT( and the matching closing delimiter is )TEXT".
Adjacent string literal concatenation
C++ automatically joins string literals placed next to each other. This works in C++98 and later:
const char* message =
"First line\n"
"Second line\n"
"Third line";
The resulting value is one string:
First line
Second line
Third line
Each \n is necessary if you want a newline in the value.
Step by Step Execution
Consider this C++ code:
#include <iostream>
int main() {
const char* message =
"Ready\n"
"Set\n"
"Go";
std::cout << message;
}
Step by step:
-
The compiler sees three string literals directly next to one another.
-
It concatenates them during compilation, as if you had written:
const char* message = "Ready\nSet\nGo"; -
\nis an escape sequence representing one newline character. -
std::coutwritesReady, then a newline, thenSet, another newline, and finallyGo.
By contrast, with a raw string:
const char* message = R"(Ready
Set
Go)";
The actual source-code line breaks inside R"( and )" become characters in the string.
Real World Use Cases
- JSON fixtures: Store a small sample API payload directly in a test.
const char* payload = R"({"status":"ok","count":3})"; - SQL queries: Keep a readable multi-line query in source code.
const char* query = R"SQL( SELECT id, email FROM users WHERE active = 1 )SQL"; - Regular expressions: Raw strings avoid doubled backslashes.
std::regex datePattern(R"(\d{4}-\d{2}-\d{2})"); - Help text and command-line output: Concatenated literals make line breaks explicit and work in older codebases.
- Unit-test expected output: A raw string can make expected multi-line output easy to compare and read.
Real Codebase Usage
In production code, choose the representation based on where the text belongs and how large it is.
-
Use raw literals for short, static, readable blocks such as test data, SQL, templates, and diagnostic messages.
-
Use adjacent literals when supporting pre-C++11 compilers or when explicit
\ncharacters make formatting clearer. -
Use
constexpr std::string_viewin C++17 and later when an immutable, non-owning view is appropriate:#include <string_view> constexpr std::string_view usage = R"(Usage: app --input FILE app --help )"; -
Put large or user-editable content in a resource file, configuration file, or embedded-resource system rather than a huge source literal. A normal
#includeinserts C++ tokens into the source file; it does not automatically read a text file and turn it into a quoted string.
A common pattern for validation or errors is to keep a stable multi-line template as a constant, then add dynamic values separately rather than attempting to build one giant literal.
Common Mistakes
Forgetting newline characters with adjacent literals
This compiles, but it does not put a newline between the words:
const char* message =
"First line"
"Second line";
// Result: "First lineSecond line"
Add \n where needed:
const char* message = "First line\n" "Second line";
Expecting a backslash at end of a source line to add a newline
const char* message = "Hello \
world";
A backslash followed by a physical newline is removed by the preprocessor during line splicing. It does not insert \n; the result is effectively "Hello world". Prefer adjacent literals or a raw string.
Indentation becomes part of a raw string
const char* text = R"(
one
two
)";
The leading newline and the four spaces before one and two are part of text. Align content carefully if whitespace matters.
Ending a raw string too early
The default raw-string terminator is )". If the content contains that exact sequence, use a custom delimiter:
const char* text = R"END(Content containing )" is safe here.)END";
Using #include as though it reads text at runtime
const char* text = #include "message.txt"; // Invalid in normal C++
#include is a preprocessing directive and must appear where the preprocessor accepts directives. It includes source tokens, not arbitrary text as a string. Read a file at runtime or use a deliberate build-time resource-generation approach instead.
Comparisons
| Approach | C++ version | Newlines in result | Best for |
|---|---|---|---|
Raw string: R"(a\nb)" written across source lines | C++11+ | Physical line breaks are preserved | JSON, SQL, regex, templates, test data |
Adjacent literals: "a\\n" "b" | C++98+ | Only where \n is written | Portable messages and explicit formatting |
Normal literal with \n | C++98+ | Only where \n is written | Short single-line source literals |
| Backslash-newline in source | C++98+ | No newline is added | Line continuation only; usually avoid for text |
| External file | Any | Depends on file contents | Large, editable, or localized content |
Raw strings improve readability when text contains many backslashes or quotes. Adjacent literals are more portable and make every newline explicit.
Cheat Sheet
// C++11+: actual source line breaks become part of the string
const char* text = R"(line 1
line 2)";
// C++98+: adjacent literals are joined by the compiler
const char* text =
"line 1\n"
"line 2";
// Custom raw delimiter when content includes )"
const char* text = R"TAG(text with )" inside)TAG";
// Explicit escaped newline in an ordinary literal
const char* text = "line 1\nline 2";
- Adjacent string literals concatenate automatically.
\nis one newline character.- Raw strings preserve physical line breaks and do not interpret most escapes.
- Whitespace used to indent raw-string content is also preserved.
- A trailing backslash before a source newline continues the source line; it does not add a newline to the string.
#includedoes not directly convert a plain text file into a C++ string literal.
FAQ
Can a normal C++ string literal span multiple source lines?
No. A physical newline inside an ordinary quoted literal is invalid. Use a raw string or adjacent literals.
Do adjacent string literals add spaces or newlines automatically?
No. "one" "two" becomes "onetwo". Add a space or \n yourself.
Are raw string literals available in C++98?
No. Raw string literals were added in C++11. Adjacent string literal concatenation works in C++98.
Does a raw string interpret \n as a newline?
No. In a raw string, the characters backslash and n stay as written. To include a newline, press Enter inside the raw string.
Can a raw string contain double quotes?
Yes. Double quotes are ordinary content unless they form the exact closing delimiter.
Why does my raw string have an unexpected blank first line?
If you put the opening delimiter on its own line, the following line break is part of the string. Put content immediately after R"( if you do not want that first newline.
Should I put a very large document in a raw string?
Usually no. For large, editable, translated, or frequently updated content, use an external resource or data file and load it deliberately.
Mini Project
Description
Create a command-line help message for a small backup tool. The project demonstrates storing readable multi-line, constant text in a C++ program with a raw string literal.
Goal
Print a neatly formatted help screen that preserves line breaks and shows command examples.
Requirements
Use a C++11 raw string literal for the help text.
Keep learning
Related questions
Advantages of Brace Initialization in C++
Learn why C++ brace initialization is often clearer and safer than other object initialization styles, with examples and common pitfalls.
Basic Rules and Idioms for Operator Overloading in C++
Learn the core rules, syntax, and common idioms for operator overloading in C++, including member vs non-member operators.
C++ Aggregates, Trivial Types, Trivially Copyable Types, and PODs Explained
Learn what aggregates, trivial types, trivially copyable types, and PODs mean in C++, how they differ, and why they matter.