サーチ…


構文

  • _Generic(代入式、generic-assoc-list)

パラメーター

パラメータ詳細
ジェネリックアソークリストジェネリックアソシエーションまたはジェネリックアソークリスト、ジェネリックアソシエーション
ジェネリック協会タイプ名:代入式ORデフォルト:代入式

備考

  1. すべての型修飾子は、 _Generic主表現の評価中に削除されます。
  2. _Genericな一次発現は翻訳段階7で評価される。したがって、文字列連結のようなフェーズは評価前に終了しています。

変数が特定の修飾型かどうかをチェックする

#include <stdio.h> 

#define is_const_int(x) _Generic((&x),  \
        const int *: "a const int",     \
        int *:       "a non-const int", \
        default:     "of other type")

int main(void)
{
    const int i = 1;
    int j = 1;
    double k = 1.0;
    printf("i is %s\n", is_const_int(i));
    printf("j is %s\n", is_const_int(j));
    printf("k is %s\n", is_const_int(k));
}

出力:

i is a const int
j is a non-const int
k is of other type

しかし、タイプジェネリックマクロが次のように実装されているとします。

#define is_const_int(x) _Generic((x), \
        const int: "a const int",     \
        int:       "a non-const int", \
        default:   "of other type")

出力は次のとおりです。

i is a non-const int
j is a non-const int
k is of other type

これは、 _Genericプライマリ式の制御式の評価のために、すべての型修飾子が削除されるためです。

タイプジェネリック印刷マクロ

#include <stdio.h>

void print_int(int x) { printf("int: %d\n", x); }
void print_dbl(double x) { printf("double: %g\n", x); }
void print_default() { puts("unknown argument"); }

#define print(X) _Generic((X), \
        int: print_int, \
        double: print_dbl, \
        default: print_default)(X)

int main(void) {
    print(42);
    print(3.14);
    print("hello, world");
}

出力:

int: 42
double: 3.14
unknown argument

型がintでもdoubleでもない場合は、警告が生成されることに注意してください。警告を削除するには、そのタイプをprint(X)マクロに追加します。

複数の引数に基づく汎用選択

型ジェネリック式の複数の引数の選択が必要で、問題の型がすべて算術型である場合、ネストされた_Generic式を避ける簡単な方法は、制御式のパラメータの追加を使用することです。

int max_int(int, int);
unsigned max_unsigned(unsigned, unsigned);
double max_double(double, double);

#define MAX(X, Y) _Generic((X)+(Y),                \
                           int:      max_int,      \
                           unsigned: max_unsigned, \
                           default:  max_double)   \
                    ((X), (Y))

ここで、制御式(X)+(Y)は、そのタイプによってのみ検査され、評価されない。選択されたタイプを決定するために、算術オペランドの通常の変換が実行されます。

より複雑な状況では、オペレータに対する複数の引数に基づいて、それらを一緒に入れ子にすることによって選択を行うことができる。

この例では、2つのintおよび/またはstring引数の組み合わせを取り、それらの合計を返す4つの外部実装関数を選択します。

int AddIntInt(int a, int b);
int AddIntStr(int a, const char* b);
int AddStrInt(const char*  a, int b );
int AddStrStr(const char*  a, const char*  b);

#define AddStr(y)                            \
   _Generic((y),         int: AddStrInt,     \
                        char*: AddStrStr,    \
                  const char*: AddStrStr )

#define AddInt(y)                            \
   _Generic((y),          int: AddIntInt,    \
                        char*: AddIntStr,    \
                  const char*: AddIntStr )

#define Add(x, y)                            \
   _Generic((x) ,        int: AddInt(y) ,    \
                       char*: AddStr(y) ,    \
                 const char*: AddStr(y))     \
                         ((x), (y))

int main( void )
{
    int result = 0;
    result = Add( 100 , 999 );
    result = Add( 100 , "999" );
    result = Add( "100" , 999 );
    result = Add( "100" , "999" );

    const int a = -123;
    char b[] = "4321";
    result = Add( a , b );

    int c = 1;
    const char d[] = "0";
    result = Add( d , ++c );
}

引数yが2回以上評価されたように見えますが、それは1ではありません。両方の引数は、通常の関数呼び出しの場合と同様に、Add: ( x , y )マクロの最後で1回だけ評価されます。


1 (引用:ISO:IEC 9899:201X 6.5.1.1汎用選択3)
汎用選択の制御式は評価されません。



Modified text is an extract of the original Stack Overflow Documentation
ライセンスを受けた CC BY-SA 3.0
所属していない Stack Overflow