Adjacent string literals are concatenated, and this is useful two ways: macros which combine strings and visualizing multi-line string literals such as you have above. Compare how that code would look otherwise:
char const help_message[] = "Usage: %s [options] files ...\n\nOptions include:\n --verbose -v Be verbose\n --help -h Print this help message\n --output -o Specify output file\n\n";
Imagine trying to maintain that instead. In addition, if you use a multi-line string literal, you have to either escape newlines or deal with whatever the source code uses, which may not be '\n'
, and you'll have to watch your indentation carefully. All of which makes the code in your example better.
Here's an example of the macro case:
#define STRINGIZE_(v) #v
#define STRINGIZE(v) STRINGIZE_(v)
#define LOCATION __FILE__ ":" STRINGIZE(__LINE__)
#define MY_ASSERT(expr) do { \
if (!(expr)) \
some_function(LOCATION ": assertion failed in " \
__PRETTY_FUNCTION__ ": " #expr); \
} while (0)
(There are alternatives to this, such as passing separate parameters, and using the GCC-specific __PRETTY_FUNCTION__
like this is deprecated too, but the rest is handy and this is a decent "real" example, IMHO.)
Other issues brought up in that code to be aware of:
- the single
#
is the preprocessor stringize operator (##
is the other special preprocessor operator, for token pasting)
- without the second stringize macro, you'll get
"filename.c:__LINE__"
- using do-while doesn't break if-else and requires the macro to be used as a statement rather than an expression
- preventing use as an expression isn't always helpful, but it is what you want for assert-like macros
Breaking if-else example:
if (cond) MY_ASSERT(blah);
else other();
Expands to:
if (cond) do { ... } while(0);
else other();
Instead of:
if (cond) if (...) ...;
else other();
Which is the incorrect and surprising:
if (cond) {
if (...) {
...;
}
else {
other();
}
}