C11_Generic:如何处理字符串文本?
使用C11中的C11_Generic:如何处理字符串文本?,c,clang,c11,C,Clang,C11,使用C11中的\u Generic功能,您如何处理字符串文本 例如: #include <stdio.h> #define foo(x) _Generic((x), char *: puts(x)) int main() { foo("Hello, world!"); return 0; } 将char*替换为char[]会让我 error: type 'char []' in generic association incomplete 据我所知,编译此文件的
\u Generic
功能,您如何处理字符串文本
例如:
#include <stdio.h>
#define foo(x) _Generic((x), char *: puts(x))
int main()
{
foo("Hello, world!");
return 0;
}
将char*
替换为char[]
会让我
error: type 'char []' in generic association incomplete
据我所知,编译此文件的唯一方法是:
\u Generic
的观点char[14]
作为类型说明符。你一定是在跟我开玩笑\u Generic
时会衰减为指针,但显然不是这样。那么,如何对字符串文本使用\u Generic
?这是唯一的两个选择吗
我在Debian上使用了Clang3.2。不幸的是,它是我访问过的唯一支持此功能的编译器,因此我无法判断它是否是编译器错误。这里有一个解决方案:
#include <stdio.h>
#define foo(x) _Generic((0,x), char*: puts(x))
int main()
{
foo("Hello, world!");
return 0;
}
这有点蹩脚,但我没有找到更好的方法使x
衰减为指向char的指针,也没有找到更好的方法以模糊的方式匹配它的类型,正如您所要求的那样,使用Apple LLVM版本4.2(clang-425.0.28)(基于LLVM 3.2svn)
根据,GCC的行为是不同的(在GCC中,字符串显然会自动衰减为\u 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;
}
叮当声的行为一直持续到。它是固定的 委员会对DR 481的答复如下: 这篇论文引发了一场长期而富有成效的讨论。委员会同意
\u Generic
提案的作者的意见,即的目的是明确避免选择合格类型,就像按大小选择阵列一样。<>代码>泛型< /C> >的目的是给C++提供一种机制来表达C++中“重载函数”的概念,尤其是一种可能的实现机制,用于实现7.77.0.7/7.P>中的原子类型泛型函数。
谢谢你,这是个不错的建议,如果很烦人的话。关于
char
与const char
:是的,但是\u Generic
模糊地增加了const
,所以我想我会利用这一点。我将编辑示例。干杯@MichaelRawson 6.5.1.1继续:“如果泛型选择具有与控制表达式类型兼容的类型名称的泛型关联,则泛型选择的结果表达式就是该泛型关联中的表达式。”并且const char*
与char*
不兼容。我不希望有任何持续的模糊性。对不起,我一定是在什么地方漏掉了星号什么的clang
的行为与您(以及标准)所描述的一样。&*
是另一个“不做任何事情”的上下文,与0类似,
强制指针衰减,但如果x
不是指针(比如说,如果您想对浮点和字符串文本使用\u Generic
),它将不起作用。您使用的sizeof
给我留下了深刻的印象。@PascalCuoq如果您是对的,(0,x)是唯一的方法。我之所以这么做,是因为编译器给了我一个警告:表达式没有删除任何效果。如果我使用(0,x)。那么,如果\u Generic
前面的语句恰好是一个表达式,您可以将其移动到\u Generic
,例如,转换为printf(“hello world\n”)_泛型(x,…)
转换成泛型((printf(“hello world\n”),x),…)。您可能还想试试((void)0),x)
是否能让编译器清楚地了解意图。@PascalCuoq-Yup(void)0
做到了。我也在clang online上尝试了你的方法,它给出了一个错误,但是稍微更改了一点表达式:\u Generic((0,x)+0)
解决了该问题。对于所有类型,以及非指针类型,*&是否都能正常工作?请注意,在6.5.1.1中,需要对泛型选择的控制表达式进行数组到指针的衰减,因此字符串文字将被视为char*:控制表达式的类型是表达式的类型,就像它经历了左值转换(脚注:左值转换删除类型限定符)、数组到指针转换或函数到指针转换一样
$ clang t.c && ./a.out
Hello, world!
#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;
}
#include <stdio.h>
#define foo(x) _Generic( ( &*(x) ), char*: puts , const char*: puts )( x )
int main()
{
foo("Hello, world!");
return 0;
}