C11 _Generic: how to deal with string literals?

前端 未结 3 1574
悲&欢浪女
悲&欢浪女 2020-12-03 10:21

Using the _Generic feature in C11, how do you deal with string literals?

For instance:

#include 
#define foo(x) _Generic(         


        
相关标签:
3条回答
  • 2020-12-03 10:41

    I have figured out a way to avoid using the clever (0,x) trick.

    If you use a string literal the type is char[s] , where s is the size of the string literal.

    How do you get that size?, use sizeof operator:

    #include <stdio.h>
    
    #define Test( x )   _Generic( ( x ) ,   char*: puts ,                   \
                                            const char*: puts ,             \
                                            const char[sizeof( x )]: puts , \
                                            char[sizeof( x )]: puts )( x )
    
    int main(void) 
    {
    
        char str[] = "This" ;
        Test( str ) ;
    
        Test( "works" ) ;
    
        char str2[10] = "!!!" ;
        Test( str2 ) ;
    
    return 0;
    }
    

    I tried compiling it with clang and Pelles and it worked.

    The only problem you still have to cast variable length arrays.

    After trying some more I found another analogue way of doing what Pascal Cuoq did, use &* operators:

    #include <stdio.h>
    #define foo(x) _Generic( ( &*(x) ), char*: puts , const char*: puts )( x )
    
    int main()
    {
        foo("Hello, world!");
        return 0;
    }
    
    0 讨论(0)
  • 2020-12-03 10:41

    The behaviour of Clang was incorrect (C11 Defect report 481) until 3.7.1. It was fixed in Clang 3.8.0, released on March 8, 2016.

    The Committee response to the DR 481 says the following:

    This paper elicited a long and productive discussion. The committee agrees with the author of the _Generic proposal that the intent was that selecting on qualified types was explicitly to be avoided as was selecting on arrays by size. The intent of _Generic was to give C a mechanism to somewhat express the notion of “overloaded function” found in C++, and in particular a possible mechanism for implementors to use to implement the atomic type generic functions from section 7.17.7.

    0 讨论(0)
  • 2020-12-03 10:47

    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)

    0 讨论(0)
提交回复
热议问题