C11_Generic:如何处理字符串文本?

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 据我所知,编译此文件的

使用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
    的观点
  • 使用
    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;
    }