Is there a way to warn or prohibit literal string concatenations such as:
const char *a = "foo" " bar";
I spent hours finding a bug in a big static array that had
const char * a[] = {"foo" "bar"};
instead of
const char * a[] = {"foo", "bar"};
Is there a way to warn or prohibit literal string concatenations such as:
const char *a = "foo" " bar";
I spent hours finding a bug in a big static array that had
const char * a[] = {"foo" "bar"};
instead of
const char * a[] = {"foo", "bar"};
Clang has a warning -Wstring-concatenation that is explicitly designed to catch such bugs:
warning: suspicious concatenation of string literals in an array initialization; did you mean to separate the elements with a comma? [-Wstring-concatenation]
char const *a[] = { "ok", "foo" "bar", "ok"};
^
,
This won't exactly work for the toy example you showed because you need to have several initializers and only miss commas in a couple of places, i.e.:
// no warning
char const *b[] = {"foo" "bar"};
// no warning
char const *c[] = {"ok", "foo" "bar"};
// no warning
char const *d[] = {"foo" "bar", "ok"};
But when you have a large number of initializers in an array and only make a typo in a couple of places, this seems ideal.
Here's a demo.
GCC doesn't appear to have an equivalent warning, but there is a request for it to be added.
Note that this only works for array initialization. Your example of
const char *x = "foo" " bar";
won't be detected by this warning (or any other that I'm aware of).
Also note that enabling this warning may yield a lot of false positives, but you can use it sparingly when trying to catch bugs.
Not really. String literal concatenation is an indispensable part of the C/C++ grammar and has many use cases. So some kind of effort is needed and that may defeat the goal of catching a blunder.
However, string concatenation works very strictly on two string literals appearing after each other with only white space in between, so breaking the white space will cause an error. E.g., in this case you could have written:
const *char[] = {("foo") ("bar")}; // Error
which would cause an error while the intended statement would not:
const *char[] = {("foo"), ("bar")}; // OK
So, in short, you cannot have some way to explicitly tell the compiler that two string literals may be concatenated and have it fail in all other cases, so you will have to tell the compiler explicitly when a string literal may not be concatenated.
Either of the macros below make it impossible to accidentally concatenate two strings.
CPP (C preprocessor) macros are awesome in general. It is also legal to have a trailing comma at the end of a list of element.
You can do something like this:
#define STRINGCOMMA(a) a,
const char *x[] = {
STRINGCOMMA("foo")
STRINGCOMMA("bar")
};
Or even:
#define QUOTESTRINGCOMMA(a) #a,
const char *x[] = {
QUOTESTRINGCOMMA(foo)
QUOTESTRINGCOMMA(bar)};
The comma is added for you, and it would be illegal for you to accidentally do it yourself.
If you are interested, it is also possible to take this concept further to allow creation of parallel lists with the same arguments, but different processing:
#define VARLIST \
DO(foo) \
DO(bar)
#define DO(a) #a,
const char *x[] = {
VARLIST
};
#undef DO
This would be useful if you wanted to create a list of enums and a list of strings, from the same list of names.
I spent hours finding a bug in a big static array ...
Well, you can do this:
char const * a [] =
{ "foo"
, "bar"
, "baz"
, "asdf"
, "ghjk"
};