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

问题描述 投票:25回答:3

使用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]作为类型说明符。你一定是在跟我开玩笑...

我的假设是当传递给_Generic时,数组会衰减到指针,但显然不是。那么,我如何将_Generic与字符串文字一起使用?那是唯一的两种选择吗?

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

c clang c11
3个回答
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)


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

3
投票

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节中的原子类型泛型函数的可能机制。

© www.soinside.com 2019 - 2024. All rights reserved.