Question

Multi-Line String Literals in C++: Raw Strings and Concatenation

cppstring-literalsrawstring

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 \n characters 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 \n for 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.

Take Quiz

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:

  1. The compiler sees three string literals directly next to one another.

  2. It concatenates them during compilation, as if you had written:

    const char* message = "Ready\nSet\nGo";
    
  3. \n is an escape sequence representing one newline character.

  4. std::cout writes Ready, then a newline, then Set, another newline, and finally Go.

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.
Take Quiz

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 \n characters make formatting clearer.

  • Use constexpr std::string_view in 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 #include inserts 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

ApproachC++ versionNewlines in resultBest for
Raw string: R"(a\nb)" written across source linesC++11+Physical line breaks are preservedJSON, SQL, regex, templates, test data
Adjacent literals: "a\\n" "b"C++98+Only where \n is writtenPortable messages and explicit formatting
Normal literal with \nC++98+Only where \n is writtenShort single-line source literals
Backslash-newline in sourceC++98+No newline is addedLine continuation only; usually avoid for text
External fileAnyDepends on file contentsLarge, 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.

Take Quiz

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.
  • \n is 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.
  • #include does 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.

Take Quiz

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.

Take Quiz

Keep learning

Related questions

View more