C言語/typeof演算子とtypeof unqual演算子
C言語には、式や型名から型を取得する typeof
演算子と typeof_unqual
演算子があります。これらを総称して typeof
演算子と呼びます。typeof
演算子は、対象の型の修飾子を維持したまま型を取得しますが、typeof_unqual
演算子は修飾子を除去した型を取得します。
構文
編集typeof
演算子と typeof_unqual
演算子の構文は以下のとおりです。
typeof(typeof-specifier-argument) typeof_unqual(typeof-specifier-argument)
typeof-specifier-argument
には式または型名を指定します。
制約
編集typeof
演算子と typeof_unqual
演算子は、ビットフィールドメンバを示す式には適用できません。
動作
編集typeof
演算子と typeof_unqual
演算子は、式または型名に対して適用されます。式に対して適用された場合、その式の型を取得します。この際、配列型や関数型は適切にポインタ型に調整されます。型名に対して適用された場合、ネストした typeof
演算子があれば再帰的に評価した上で、その型名と同じ型を取得します。
typeof_unqual
演算子の結果は、typeof
演算子で取得した型から修飾子を取り除いた非アトミック型となります。一方、typeof
演算子はすべての修飾子を維持します。
式の型が可変長修飾型の場合、その式は評価されます。それ以外の場合は評価されません。
使用例
編集typeof
演算子と typeof_unqual
演算子は様々な場面で使用できます。以下にいくつかの使用例を示します。
- 式の型を調べる例
typeof(1+1) // int型
- 型名を調べる例
const int x = 1; typeof(x) y; // constを維持したconst int型 typeof_unqual(x) z; // 修飾子を除去したint型
- 配列型の例
const char* animals[] = {"aardvark", "bluejay", "catte"}; typeof(animals) arr1; // const char* const[3]型 typeof_unqual(animals) arr2; // const char*[3]型
- 関数ポインタ型の例
void f(int); typeof(f) g; // void(int)型 typeof_unqual(f) h; // void(int)型
- ネストした型の例
typeof(typeof_unqual(typeof(argc))) x; // int型
sizeofとの等価性
編集sizeof
演算子とtypeof
演算子が同じ型を推論することから、以下のようなプログラムに制約違反はありません。
static_assert(sizeof(typeof('p')) == sizeof(int)); static_assert(sizeof(typeof('p')) == sizeof('p')); static_assert(sizeof(typeof((char)'p')) == sizeof(char));
実行時評価
編集可変長配列(VLA)のサイズは実行時に決まるため、そのサイズを使った型推論は実行時に行われます。
#include <stddef.h> size_t vla_size(int n) { typedef char vla_type[n+3]; vla_type b; return sizeof(typeof_unqual(b)); // 実行時にサイズが決まる }
配列からポインタへのdecayが発生しない例
編集配列型に対してtypeof
演算子を適用した場合、配列からポインタへの型の変換(decay)は発生しません。
int main() { typeof(typeof(const char*)[4]) y = {"a", "b", "c", "d"}; // 4要素の"const char*"型の配列 return 0; }
まとめ
編集typeof
演算子とtypeof_unqual
演算子は、式や型名から型を取得する強力な機能です。修飾子の維持/除去、配列型やポインタ型への対応、ネストした型での使用など、様々な用途に使えます。実行時の型推論にも対応しており、可変長配列のサイズ決定時に活用できます。これらの演算子を上手く活用することで、型の安全性を高めたり、コードの可読性を向上させたりできます。