使用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。不幸的是,它是我访问过的唯一支持此功能的编译器,所以我不知道它是否是编译器错误。
这是一个解决方案:
#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)
我已经找到了避免使用聪明的(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;
}
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节中的原子类型泛型函数的可能机制。