typeof
typeof
は引数の型を表す特殊な演算子である。引数には型名や式を渡すことができる。これにより事実上の型推論の実現が可能になる。コンパイラによっては__typeof__
や__typeof
として同等の機能が提供されている。
int i = 0;
typeof(i) j = i; // 変数jはint型になる
typeof('\0') k = 'c'; // 値指定も可能
// a, b いずれも`int *`型となる
typeof(int *) a = &i; // 型名を指定
typeof(a) b = &i; // 式を指定
// 変数`c`はisalpha関数の戻り値型`int`になる
typeof(isalpha(0)) c; // isalpha関数は呼ばれない
c = isalpha('a');
typeof(1L) d; // 変数`d`はlong型になる
assert(sizeof(d) == sizeof(long));
typeofで求められた型はtypedefで定義された型のように振る舞う。これによってポインタ型のような表現が可能となる。
int i = 0;
// 変数`b`もポインタ変数として宣言される
typeof(int *) a, b;
a = &i;
b = &i; // OK
// 変数`d`は`int`型として宣言される
int *c, d;
c = &i;
d = &i; // ERROR
typeofの活用例
一般的に、typeofは汎用的な機能やライブラリ等のレイヤーで利用される。SWAPマクロの一時変数型を導き出す際などが良い例である。
#define SWAP(a, b) do { typeof(a) tmp = a; a = b; b = tmp; } while (0)
int a = 1, b = 2;
SWAP(a, b);
printf("%d%d", a, b); // 21
typeofによる一時変数の実現は、マクロ引数が二重に評価されてしまう問題への回避にも繋がる。
#define max(a, b) ({ \
typeof(a) A = (a); \
typeof(b) B = (b); \
A < B ? B : A; \
})
max(0, isdigit('9')); // isdigit関数は一度だけ呼ばれる
#define max(a, b) ((a) < (b) ? (b) : (a))
max(0, isdigit('9')); // isdigit関数は二度呼ばれる
typeofは移植性の問題もあるため、アプリケーションレイヤでは無闇に使わないようにしたい。
typeofが利用できない場合
typeofキーワード自体はGNUコンパイラの独自拡張であり、全てのコンパイラで利用出来る機能とは限らない。
Clangコンパイラではtypeof
利用時に以下のようなエラーが発生する。
C言語コンパイラ
Implicit declaration of function 'typeof' is invalid in C99
Expected expression
C++コンパイラ
Unknown type name 'typeof'; did you mean 'typedef'?
C++ requires a type specifier for all declarations
コンパイラによっては同等の機能が__typeof__
や__typeof
として提供されている場合があるのでそちらを利用すると良い。
C++の場合の対処法
C++の場合はtypeofの代わりにdecltype
が利用できる。
int i = 0;
int *p = &i; // `decltype(int *)`等の型指定は出来ない
decltype(p) q = p;
printf("%d", p == q);
GNU拡張を有効にする場合
Clangコンパイラでも、コンパイラオプションでGNU拡張を有効にすることで、typeofの利用が可能になる。C言語コンパイラの場合は-std=gnu99
(C99)または-std=gnu11
(C11)の指定を行い、C++コンパイラの場合は-std=gnu++11
(C++11)または-std=gnu++14
(C++14)の指定を行えば良い。
$ clang hello.c -std=gnu99
$ clang hello.cpp -std=gnu++99
Xcodeの場合はC/C++ Language Dialect
項目で上記オプションの選択が可能になる。
TARGETS → Build Settings → C Language Dialect
TARGETS → Build Settings → C++ Language Dialect