25

使用_GenericC11 中的特性,你如何处理字符串字面量?

例如:

#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。不幸的是,它是我可以访问的唯一支持此功能的编译器,所以我无法判断它是否是编译器错误。

4

3 回答 3

21

这是一个解决方案:

#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)。

根据Jens Gustedt 的这篇博客文章,GCC 的行为是不同的(在 GCC 中,字符串显然会自动衰减为_Generic上下文中的指针)。

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

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

于 2013-09-17T18:36:54.000 回答
15

我想出了一种方法来避免使用这个聪明的(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;
}
于 2014-11-10T21:47:48.860 回答
5

在3.7.1之前,Clang 的行为是不正确的(C11 缺陷报告 481)它已在2016 年 3 月 8 日发布的 Clang 3.8.0 中修复。

委员会对 DR 481 的回应如下:

这篇论文引起了长期而富有成效的讨论。委员会同意该_Generic提案的作者,其意图是明确避免选择合格的类型,就像选择按大小排列的数组一样。的目的_Generic是为 C 提供一种机制,在某种程度上表达 C++ 中的“重载函数”的概念,特别是实现者用于实现 7.17.7 节中的原子类型泛型函数的可能机制。

于 2019-03-28T07:29:37.777 回答