Using the _Generic
feature in C11, how do you deal with string literals?
For instance:
#include <stdio.h> #define foo(x) _Generic((x), char *: puts(x)) int main() { foo("Hello, world!"); return 0; }
gives this error on clang:
controlling expression type 'char [14]' not compatible with any generic association type
Replacing char *
with char[]
gives me
error: type 'char []' in generic association incomplete
The only ways (to my knowledge) of getting this to compile are:
_Generic
in the first place.char[14]
as the type specifier. You have got to be kidding me...My assumption was that arrays would decay to pointers when passed to _Generic
, but evidently not. So, how do I use _Generic
with string literals? Are those the only two options?
I'm using clang 3.2 on Debian. Unfortunately, it's the only compiler I have access to that supports this feature, so I can't tell if it's a compiler bug or not.
A "string literal" is a sequence of characters from the source character set enclosed in double quotation marks (" "). String literals are used to represent a sequence of characters which, taken together, form a null-terminated string. You must always prefix wide-string literals with the letter L.
The behavior is undefined if a program attempts to modify any portion of a string literal. Modifying a string literal frequently results in an access violation because string literals are typically stored in read-only memory.
C Language Undefined behavior Modify string literalAttempting to modify the string literal has undefined behavior. However, modifying a mutable array of char directly, or through a pointer is naturally not undefined behavior, even if its initializer is a literal string.
The compiler scans the source code file, looks for, and stores all occurrences of string literals. It can use a mechanism such as a lookup table to do this. It then runs through the list and assigns the same address to all identical string literals.
Here is a solution:
#include <stdio.h> #define foo(x) _Generic((0,x), char*: puts(x)) int main() { foo("Hello, world!"); return 0; }
This compiles and produces:
$ clang t.c && ./a.out Hello, world!
It is somewhat lame, but I did not find any better way to make x
decay to a pointer to char nor to match its type in the fuzzy fashion that you require, with Apple LLVM version 4.2 (clang-425.0.28) (based on LLVM 3.2svn).
According to this blog post by Jens Gustedt, GCC's behavior is different (in GCC, strings automatically decay to pointer in a _Generic
context, apparently).
By the way, in C, the type of a string literal is array of char
, not of const char
. Rejecting char []
as type-name in a generic-association is not a compiler bug:
A generic selection shall have no more than one default generic association. The type name in a generic association shall specify a complete object type other than a variably modified type. (6.5.1.1:2 with my emphasis)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With