1. ホーム
  2. c

[解決済み] C言語で変数が特定の型であるかどうかを確認する(2つの型を比較する)にはどうすればよいですか?

2023-02-25 05:22:27

質問

C 言語 (C++/C# ではありません) で、ある変数が特定の型であるかどうかを調べるにはどうしたらよいでしょうか。

例えば、こんな感じです。

double doubleVar;
if( typeof(doubleVar) == double ) {
    printf("doubleVar is of type double!");
}

あるいはもっと一般的に どのように二つの型を比較すれば compare(double1,double2) が真と評価されるように、そして compare(int,double) は false と評価されます。また、異なる構成の構造体も同様に比較したいです。

基本的に、私は "struct a" と "struct b" 型の変数を操作する関数を持っています。あることを "struct a" 変数で行い、別のことを "struct b" 変数で行いたいと思います。C言語ではオーバーロードがサポートされておらず void のポインタは型情報を失うので、型チェックをする必要があります。ところで、このように typeof 演算子を持つ意味は何でしょうか?


sizeofメソッドは、私にとって実用的な回避策になりそうです。ご教授ありがとうございます。コンパイル時に型が分かっているので、まだ少し不思議な感じがしますが、マシン内のプロセスを想像すると、なぜ情報が型ではなく、バイトサイズで保存されるのかが分かります。サイズは、アドレス以外に本当に関連する唯一のものです。

どのように解決するのですか?

変数の型の取得は、今のところ、C11では _Generic 一般的な選択で可能です。これはコンパイル時に動作します。

の構文と少し似ています。 switch . 以下はそのサンプルです ( この回答 ):

    #define typename(x) _Generic((x),                                                 \
            _Bool: "_Bool",                  unsigned char: "unsigned char",          \
             char: "char",                     signed char: "signed char",            \
        short int: "short int",         unsigned short int: "unsigned short int",     \
              int: "int",                     unsigned int: "unsigned int",           \
         long int: "long int",           unsigned long int: "unsigned long int",      \
    long long int: "long long int", unsigned long long int: "unsigned long long int", \
            float: "float",                         double: "double",                 \
      long double: "long double",                   char *: "pointer to char",        \
           void *: "pointer to void",                int *: "pointer to int",         \
          default: "other")

実際にコンパイル時の手動型チェックに利用するためには、コンパイル時に enum を、期待する全ての型と一緒に定義します。

    enum t_typename {
        TYPENAME_BOOL,
        TYPENAME_UNSIGNED_CHAR,
        TYPENAME_CHAR,
        TYPENAME_SIGNED_CHAR,
        TYPENAME_SHORT_INT,
        TYPENAME_UNSIGNED_CHORT_INT,
        TYPENAME_INT,
        /* ... */
        TYPENAME_POINTER_TO_INT,
        TYPENAME_OTHER
    };

そして _Generic を使って型合わせをします。 enum :

    #define typename(x) _Generic((x),                                                       \
            _Bool: TYPENAME_BOOL,           unsigned char: TYPENAME_UNSIGNED_CHAR,          \
             char: TYPENAME_CHAR,             signed char: TYPENAME_SIGNED_CHAR,            \
        short int: TYPENAME_SHORT_INT, unsigned short int: TYPENAME_UNSIGNED_SHORT_INT,     \
              int: TYPENAME_INT,                     \
        /* ... */                                    \
            int *: TYPENAME_POINTER_TO_INT,          \
          default: TYPENAME_OTHER)