Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C11 _Generic: how to deal with string literals?

Tags:

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:

  1. Cast the string literal to an appropriate type. This is ugly and (in my view) defeats the point of _Generic in the first place.
  2. Use 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.

like image 764
Michael Rawson Avatar asked Sep 17 '13 18:09

Michael Rawson


People also ask

How do you use string literals?

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.

Is it possible to modify a string literal?

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.

Is it possible to modify a string literal in C?

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.

How does compiler process string literal?

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.


1 Answers

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)

like image 151
Pascal Cuoq Avatar answered Nov 04 '22 04:11

Pascal Cuoq