25

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

(私の知る限り)これをコンパイルする唯一の方法は次のとおりです。

  1. 文字列リテラルを適切な型にキャストします。これは醜く、(私の見解では)_Genericそもそものポイントを無効にします。
  2. char[14]型指定子として使用します。あなたはをからかっている必要があります...

私の仮定では、配列は に渡されたときにポインターに減衰します_Genericが、明らかにそうではありませんでした。では、文字列リテラルをどのように使用すればよいでしょうか? _Generic選択肢はこの2つだけですか?

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ですが、Apple LLVM バージョン 4.2 (clang-425.0.28) (LLVM ベース3.2svn)。

Jens Gustedt によるこのブログ投稿によると、GCC の動作は異なります (GCC では、文字列は_Genericコンテキスト内で自動的にポインターに減衰するようです)。

ところで、C では、文字列リテラルの型はcharではなく の配列ですconst chargeneric-associationtype-namechar []として拒否することは、コンパイラのバグではありません。

一般的な選択には、デフォルトの一般的な関連付けが 1 つしかありません。一般的な関連付けの型名は、可変的に変更された型以外の完全なオブジェクト型を指定する必要があります。(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 に答える