C11 _Generic: how to deal with string literals?

本秂侑毒 提交于 2019-11-27 14:18:26

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 Gusted, 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)

2501

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;
}

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.

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!