549

Is there any way to have multi-line plain-text, constant literals in C++, à la Perl? Maybe some parsing trick with #includeing a file? I can't think of one, but boy, that would be nice. I know it'll be in C++0x.

kokociel
  • 497
  • 6
  • 17
rlbond
  • 65,341
  • 56
  • 178
  • 228
  • 1
    Generally you don't want to embed string literals into code. For I18N and L10N it is preferable to put string literals into a configuration file that is loaded at run time. – Martin York Jul 16 '09 at 07:09
  • 58
    There are enough cases where putting string literals into code is not a problem: if the string isn't used to represent it to the user; i.e.: SQL statements, file names, registry key names,command lines to be executed, ... – mmmmmmmm Jul 16 '09 at 07:18
  • 3
    @Martin: It can still be useful to know, however. I've done it to break up complex regexs, for example. – Boojum Jul 16 '09 at 07:22

10 Answers10

740

Well ... Sort of. The easiest is to just use the fact that adjacent string literals are concatenated by the compiler:

const char *text =
  "This text is pretty long, but will be "
  "concatenated into just a single string. "
  "The disadvantage is that you have to quote "
  "each part, and newlines must be literal as "
  "usual.";

The indentation doesn't matter, since it's not inside the quotes.

You can also do this, as long as you take care to escape the embedded newline. Failure to do so, like my first answer did, will not compile:

const char *text2 =
  "Here, on the other hand, I've gone crazy \
and really let the literal span several lines, \
without bothering with quoting each line's \
content. This works, but you can't indent.";

Again, note those backslashes at the end of each line, they must be immediately before the line ends, they are escaping the newline in the source, so that everything acts as if the newline wasn't there. You don't get newlines in the string at the locations where you had backslashes. With this form, you obviously can't indent the text since the indentation would then become part of the string, garbling it with random spaces.

unwind
  • 391,730
  • 64
  • 469
  • 606
  • 3
    I have been told in the past that the first option can be up to implementation, however I've yet to find a compiler that doesn't honor that syntax. – Jason Mock Oct 22 '10 at 18:48
  • 34
    @Jason: it was not necessarily a part of pre-C89 compilers, but it is defined in C89 and therefore is supported essentially everywhere. – Jonathan Leffler Apr 04 '11 at 14:25
  • 4
    Also, if you really want the string formatted on multiple lines in c++98 just substitute \n for the terminating space on each quoted string fragment. C++11 raw literals are still my favorite. – emsr Sep 22 '11 at 03:46
  • 3
    @unwind Note that newline at the end of source line is not made part of the string, it's just skipped. If you want a newline as part of the string, you need to have \n\ at the end of the line. – hyde Apr 21 '13 at 07:39
  • 2
    There's nasty bug in Microsoft Visual Studio. If you use backslashes at the end of lines, then it automatically indents the text inside the string. – palota Jan 19 '14 at 21:18
  • @hyde Yeah, that wasn't very well put. I've tried to improve it, thanks. Also, this is old. :) – unwind Feb 15 '17 at 12:01
  • @unwind answered in 2009, commented on 2013, edited in 2017... well... :) – hyde Feb 15 '17 at 20:02
  • What is the beautiful now in 2017 that you can do a multiline string as 'std::string_view( "This text is pretty long, but will be " "concatenated into just a single string. "... );' and you'll finally have pointer and size defined at compile time. – Waldemar Mar 10 '17 at 15:37
597

In C++11 you have raw string literals. Sort of like here-text in shells and script languages like Python and Perl and Ruby.

const char * vogon_poem = R"V0G0N(
             O freddled gruntbuggly thy micturations are to me
                 As plured gabbleblochits on a lurgid bee.
              Groop, I implore thee my foonting turlingdromes.   
           And hooptiously drangle me with crinkly bindlewurdles,
Or I will rend thee in the gobberwarts with my blurlecruncheon, see if I don't.

                (by Prostetnic Vogon Jeltz; see p. 56/57)
)V0G0N";

All the spaces and indentation and the newlines in the string are preserved.

These can also be utf-8|16|32 or wchar_t (with the usual prefixes).

I should point out that the escape sequence, V0G0N, is not actually needed here. Its presence would allow putting )" inside the string. In other words, I could have put

                "(by Prostetnic Vogon Jeltz; see p. 56/57)"

(note extra quotes) and the string above would still be correct. Otherwise I could just as well have used

const char * vogon_poem = R"( ... )";

The parens just inside the quotes are still needed.

Drew Dormann
  • 59,987
  • 13
  • 123
  • 180
emsr
  • 15,539
  • 6
  • 49
  • 62
  • 35
    This is really what I want, the ability to avoid quotes, backslash-Ns, escapes, and still have newlines appear in the actual string. This is handy for embedded code (e.g. shaders or Lua). Unfortunately, we aren't all using C++-0x yet. :-( – mlepage Jul 18 '12 at 14:40
  • 2
    I was considering this for embedded SQL and Python scripts myself. I was hoping for your sake if maybe gcc would let it slide through in C++98 mode but, alas, no. – emsr Jul 18 '12 at 15:16
  • This doesn't compile for me in Visual Studio 2012. Are there any things that have to be set on the project or files to include? – jjxtra Jan 30 '13 at 23:36
  • 3
    I am more used to clang and gcc. In thise compilers you have to set a flag for C++0x or c++11. Lookin n a MS website it looks like they don't have raw literals yet. i understand that MS will release new compiler updates more quickly as C++ features get implemented. Look for Visual C++ Compiler November 2012 CTP [http://www.microsoft.com/en-us/download/details.aspx?id=35515] for the latest bleeding edge. – emsr Jan 31 '13 at 01:17
  • I know we're not supposed to be hard coding strings and maybe that's why microsoft isn't supporting this yet. But if you've got unit tests this is an awesome feature where you can throw a JSON test case in without having to do formatting. – David Jun 12 '13 at 17:35
  • Delimiter (V0G0N in your case) doesnt seem to be necessary in c++11. `R"( asdasd)))) )"` seems to work just fine. – Kamil Szot Jun 01 '14 at 19:34
  • @KamilSzot But I'll bet this wouldn't: `R"( asdasd))" )";` – JimB Feb 02 '16 at 23:06
  • @JimB Yes. It's even described in the answer. I must have missed it when I commented. – Kamil Szot Feb 03 '16 at 16:56
  • This seems to take precedence over comments, *as it should*, so it is also helpful if you want to quickly "comment *out*" a section of code that itself includes multi-line comments. Instead of `/*` then `*/` and changing the ending `*/`'s to `* /` within, you can just - at the beginning - declare `char* comment = R"(` and at the end finish it off with `)";`! Very useful if you want to omit a huge section of code or something that's heavily-commented with `/* ... */` comments instead of `// ...` comments. – rsethc Jun 10 '17 at 10:31
  • 5
    @rsethc Just use `#if 0` … `#endif` to comment out blocks of code. Nests too. – bobbogo Sep 12 '17 at 17:23
  • 1
    I don't suppose @rlbond would consider changing the accepted answer? The one currently accepted was correct at the time it was written, but this is definitely the proper answer for modern times. – GrandOpener Feb 26 '20 at 23:24
64

You can also do this:

const char *longString = R""""(
This is 
a very 
long 
string
)"""";
Raydelto Hernandez
  • 2,200
  • 2
  • 16
  • 11
32

#define MULTILINE(...) #__VA_ARGS__
Consumes everything between the parentheses.
Replaces any number of consecutive whitespace characters by a single space.

  • 1
    You can add `\n` if you need newlines – Simon Jul 01 '13 at 14:11
  • Note that `\` (and hence `\n`) is copied literally, but `"` is converted into `\"`. So `MULTILINE(1, "2" \3)` yields `"1, \"2\" \3"`. – Andreas Spindler Sep 11 '13 at 12:58
  • @AndreasSpindler Quotes and backslashes alike are escaped by (additional) backslashes as long as they appear inside a string or character literal token. Not sure what's your point. It is illegal to have an unmatched quote (double or single), so contractions don't work, or an odd number of them anyway, which is probably the biggest downside. +1 anyway. "Real programmers" always use contractions in pairs with no intervening newline so the single quotes balance. – Potatoswatter Oct 14 '13 at 04:28
  • The point is that he wrote "consumes everything between parentheses". – Andreas Spindler Oct 14 '13 at 14:33
31

A probably convenient way to enter multi-line strings is by using macro's. This only works if quotes and parentheses are balanced and it does not contain 'top level' comma's:

#define MULTI_LINE_STRING(a) #a
const char *text = MULTI_LINE_STRING(
  Using this trick(,) you don't need to use quotes.
  Though newlines and     multiple     white   spaces
  will be replaced by a single whitespace.
);
printf("[[%s]]\n",text);

Compiled with gcc 4.6 or g++ 4.6, this produces: [[Using this trick(,) you don't need to use quotes. Though newlines and multiple white spaces will be replaced by a single whitespace.]]

Note that the , cannot be in the string, unless it is contained within parenthesis or quotes. Single quotes is possible, but creates compiler warnings.

Edit: As mentioned in the comments, #define MULTI_LINE_STRING(...) #__VA_ARGS__ allows the use of ,.

bcmpinc
  • 3,202
  • 29
  • 36
  • For a project in which I wanted to include some lua code snippets in c++, I ended up writing a small python script, in which I entered the multiline strings, and let that generate a c++ source file. – bcmpinc Jul 16 '12 at 16:39
  • Perfect for me, adding a huge multi-line float-list string from a collada file for unit testing. I didn't fancy putting quotes everywhere, I needed a copy&paste solution. – Soylent Graham Aug 01 '12 at 11:39
  • 9
    You can use `#define MULTILINE(...) #__VA_ARGS__` if you want your string to contain commas. – Simon Jul 01 '13 at 14:09
  • 2
    Note this will strip out most extra whitesapce (including all `\n` and `\r`), which is kind of handy for some cases and fatal for others. – BCS Oct 08 '13 at 21:35
29

You can just do this:

const char *text = "This is my string it is "
     "very long";
Eric
  • 6,364
  • 1
  • 32
  • 49
15

Just to elucidate a bit on @emsr's comment in @unwind's answer, if one is not fortunate enough to have a C++11 compiler (say GCC 4.2.1), and one wants to embed the newlines in the string (either char * or class string), one can write something like this:

const char *text =
  "This text is pretty long, but will be\n"
  "concatenated into just a single string.\n"
  "The disadvantage is that you have to quote\n"
  "each part, and newlines must be literal as\n"
  "usual.";

Very obvious, true, but @emsr's short comment didn't jump out at me when I read this the first time, so I had to discover this for myself. Hopefully, I've saved someone else a few minutes.

CXJ
  • 4,301
  • 3
  • 32
  • 62
12

Since an ounce of experience is worth a ton of theory, I tried a little test program for MULTILINE:

#define MULTILINE(...) #__VA_ARGS__

const char *mstr[] =
{
    MULTILINE(1, 2, 3),       // "1, 2, 3"
    MULTILINE(1,2,3),         // "1,2,3"
    MULTILINE(1 , 2 , 3),     // "1 , 2 , 3"
    MULTILINE( 1 , 2 , 3 ),   // "1 , 2 , 3"
    MULTILINE((1,  2,  3)),   // "(1,  2,  3)"
    MULTILINE(1
              2
              3),             // "1 2 3"
    MULTILINE(1\n2\n3\n),     // "1\n2\n3\n"
    MULTILINE(1\n
              2\n
              3\n),           // "1\n 2\n 3\n"
    MULTILINE(1, "2" \3)      // "1, \"2\" \3"
};

Compile this fragment with cpp -P -std=c++11 filename to reproduce.

The trick behind #__VA_ARGS__ is that __VA_ARGS__ does not process the comma separator. So you can pass it to the stringizing operator. Leading and trailing spaces are trimmed, and spaces (including newlines) between words are compressed to a single space then. Parentheses need to be balanced. I think these shortcomings explain why the designers of C++11, despite #__VA_ARGS__, saw the need for raw string literals.

Andreas Spindler
  • 7,568
  • 4
  • 43
  • 34
9
// C++11. 
std::string index_html=R"html(
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>VIPSDK MONITOR</title>
    <meta http-equiv="refresh" content="10">
</head>
<style type="text/css">
</style>
</html>
)html";
user3635122
  • 138
  • 1
  • 2
-7

Option 1. Using Boost library, you can declare the string as below:

const boost::string_view helpText = "This is very long help text.\n"
      "Also more text is here\n"
      "And here\n"

// Pass help text here
setHelpText(helpText);

Option 2. If Boost is not available in your project, you can use std::string_view() in modern C++.

user16217248
  • 3,119
  • 19
  • 19
  • 37
piyu2cool
  • 27
  • 4