使用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
获得此编译的唯一方法(据我所知)是:
_Generic
。char[14]
作为类型说明符。你 开玩笑吧...... 我的假设是数组在传递给_Generic
时会衰减到指针,但显然不是。那么,如何我如何使用_Generic
字符串文字?那是唯一的两种选择吗?
我在Debian上使用 clang 3.2。不幸的是,它是我访问过的唯一支持此功能的编译器,所以我不知道它是否是编译器错误。
答案 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节中的原子类型泛型函数的一种机制。