C11 _Generic:如何处理字符串文字?

时间:2013-09-17 18:18:27

标签: c clang c11

使用C11中的_Generic功能,您如何处理字符串文字?

例如:

#include <stdio.h>
#define foo(x) _Generic((x), char *: puts(x))

int main()
{
    foo("Hello, world!");
    return 0;
}

在clang上给出了这个错误:

controlling expression type 'char [14]' not compatible with any generic association type

char *替换char[]给我

error: type 'char []' in generic association incomplete

获得此编译的唯一方法(据我所知)是:

  1. 将字符串文字转换为适当的类型。这很丑陋(在我看来)首先打败了_Generic
  2. 使用char[14]作为类型说明符。你 开玩笑吧......
  3. 我的假设是数组在传递给_Generic时会衰减到指针,但显然不是。那么,如何我如何使用_Generic字符串文字?那是唯一的两种选择吗?

    我在Debian上使用 clang 3.2。不幸的是,它是我访问过的唯一支持此功能的编译器,所以我不知道它是否是编译器错误。

3 个答案:

答案 0 :(得分:20)

这是一个解决方案:

#include <stdio.h>
#define foo(x) _Generic((0,x), char*: puts(x))

int main()
{
    foo("Hello, world!");
    return 0;
}

编译并生成:

$ clang t.c && ./a.out 
Hello, world!

它有点蹩脚,但我没有找到任何更好的方法使x衰减到指向char的指针,也不能以模糊方式匹配它的类型,Apple LLVM版本4.2(clang- 425.0.28)(基于LLVM 3.2svn)。

根据this blog post by Jens Gusted,GCC的行为是不同的(在GCC中,字符串会自动衰减到_Generic上下文中的指针,显然)。

顺便说一下,在C中,字符串文字的类型是char的数组,而不是const char的数组。在泛型关联中拒绝char []类型名称不是编译器错误:

  

通用选择应具有不超过一个默认通用关联。泛型关联中的类型名称应指定除可变修改类型之外的完整对象类型。 (重点是6.5.1.1:2)

答案 1 :(得分:13)

我已经想出了一种避免使用聪明的(0,x)技巧的方法。

如果您使用字符串文字,则类型为char[s],其中s是字符串文字的大小。

如何获得该尺寸?使用sizeof运算符:

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

我尝试用clang和Pelles编译它并且它有效。

你仍然需要构建可变长度数组的唯一问题。

在尝试了一些之后,我发现了另一种模拟方式 Pascal Cuoq做了,使用&*运营商:

#include <stdio.h>
#define foo(x) _Generic( ( &*(x) ), char*: puts , const char*: puts )( x )

int main()
{
    foo("Hello, world!");
    return 0;
}

答案 2 :(得分:2)

Clang的行为在incorrect (C11 Defect report 481)之前一直为3.7.1。它已在Clang 3.8.0, released on March 8, 2016中修复。

委员会对DR 481的答复如下:

  

本文引起了长期而富有成果的讨论。该委员会同意_Generic提议的作者的观点,即意图是明确避免选择合格类型,就像避免按大小选择数组一样_Generic的目的是为C提供某种机制,以某种方式表达C ++中的“重载函数”的概念,尤其是实现者可以用来实现第7.17.7节中的原子类型泛型函数的一种机制。