【C/C++】typeof演算子

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項目で上記オプションの選択が可能になる。

TARGETSBuild Settings → C Language Dialect
TARGETSBuild Settings → C++ Language Dialect
広告
広告