typedef(タイプデフ)は、プログラミング言語のCおよびC++におけるキーワード(予約語)である。このキーワードはデータ型に新しい名前(エイリアス、シノニム)をつけるために使用される。プログラマが容易にソースコードを記述・理解できるようにすることが目的である。

## 使用例

まず`typedef`を使わない例を示す。

この関数は入力`x`が偶数であれば1を、奇数であれば0を返す。しかし、次のように`int`型の別名として論理型(ブーリアン型)を定義し、関数の戻り値の型の名前として使用することで、戻り値の意味を明確化できる。

真偽値 (boolean) は通例0を偽、0以外を真とすることから、関数の仕様がより明確となっている。サフィックス`_t`は、typedefによる型エイリアスであることを分かりやすくするために付けられることが多い(size\_tやtime\_tなど)。

また、typedefは長大で複雑な型名を単純化するために用いられることもある。

次に、構造体を使った例を示す。

ここでは、ユーザー定義の型`my_struct`が定義されている。`my_struct`型の変数を宣言するために、C言語では以下のように`struct`キーワードが必要である。

ここで、構造体宣言の後に、以下の行を追加してみる。

これにより、`my_struct`型の変数を宣言するためには、以下のコードで十分となる。

同じことは、以下のコードでも行うことができる。

構造体のタグ名を省略することもできる。この場合、タグ名は処理系によって自動生成される。

構造体のタグ名と別名を同一にすることもできる。

以上の`typedef`活用は構造体だけに限らず、共用体`union`や列挙型`enum`の定義時にも同様に適用可能である。

typedefは、自己参照構造体へのポインタの作成を簡単にすることもできる。以下にコード例を示す。

通常、ある型のポインタ型変数を宣言する際、それぞれの変数名の前にアスタリスク`*`を記述する必要がある。

プログラマは`errptr`がポインタ型`node_t *`であることを想定しているが、typoにより`errptr`は値型`node_t`であると定義されてしまっている。これは微妙な構文エラーを引き起こす。

新たに`node_t *`型を定義することでこのような記述ミスを回避できる。以下のコードがその例である。

これにより、`errptr`を含めて全ての変数が`node_t *`型であることが保証される。

再代入や書き換えが不可能な文字列定数の配列を定義するときも、`typedef`を利用することで分かりやすくなる。

関数へのポインタを利用する場合も `typedef` を利用することで可読性を向上できる可能性がある。

なお、上記は以下のようにも書ける。

関数型もしくは関数ポインタ型のエイリアスを定義しておくと、特にコールバック関数へのポインタを引数として受け取る関数を定義するときに記述性や可読性が向上する。

配列に対して `typedef` を利用することもできる。

なお、以下のようなコードに対する動作は未定義となる。グローバルスコープを持ち、アンダースコア`_`で始まる識別子、もしくは`_`で始まり、その次が大文字の識別子は予約済み識別子であり、それを宣言または定義した場合は動作未定義とされているからである。

### マクロとの比較

C/C++にはテキストの置換機能としてマクロも備わっているが、型名の置換に使うには問題がある。まず、ポインタ型を正しく扱えない。

typedefであればポインタ型を正しく扱える。

また、マクロは乱暴な置換を行なうことから、意図しない置換による原因特定のしにくいコンパイルエラーを引き起こすこともある。

## C++

C言語と異なり、C++において構造体、共用体、列挙型、クラス型の変数を宣言する際は、`struct`、`union`、`enum`、`class`キーワードの使用はオプションとなっており、あいまいさがないかぎり省略できる。例えば、

という定義さえあれば、`typedef`エイリアスを明示的に定義したり、`struct`キーワードを明示的に使用したりせずとも、

と宣言できる。

C++ではクラス(あるいは構造体)内部で`typedef`を使用することで、クラス スコープのシノニムを定義することができるため、テンプレートを使用したジェネリックプログラミングやダックタイピングに都合がよい。C++標準ライブラリのSTLの実装では、このテクニックが利用されている。

### C++のusingエイリアス宣言

C++では`typedef`をC言語同様にエイリアス宣言のために利用できるが、C++11では`using`キーワードによる文法も追加された。

C++11では、上記は以下のようにも書ける。

なお、`typedef`はテンプレート化できないが、C++11では`using`によるエイリアステンプレートが追加された。

## 批判と利点

一部の人々は、`typedef`を広範に使用することに反対している。ほとんどの議論は、`typedef`は単に変数の実際のデータ型を隠すだけであるという考えに集中する。例えば、Linuxカーネルハッカーであり、ドキュメント作成を行っているグレッグ・クロー=ハートマン(Greg Kroah-Hartman)は、関数プロトタイプ宣言を除いて、`typedef`の使用をやめさせようとしている。彼は、`typedef`を使用することが、必要以上にコードを混乱させるだけでなく、プログラマが巨大な構造体を単純な型と誤認識して使用してしまうことがあると主張している。

しかし、`typedef`を推奨して、広範に使用することに大賛成する人々もいる。特に、C言語を発明したブライアン・カーニハン (Brian W. Kernighan) とデニス・リッチー (Dennis M. Ritchie) はプログラミング言語C(英:The C Programming Language)というC言語の定義書に、`typedef`の利用に対するメリットを2つ述べている。まず第一は、ソフトウェアをマルチプラットフォーム展開する際に、ソースコードの移植性(ポータビリティ)を向上させる手段として重要なことである。データ型の改良あるいは変更が必要になるときに、必要な変更はただ1つだけの`typedef`の宣言箇所であり、`typedef`シノニムを利用してさえいれば多くの箇所を変更する必要がなくなる。第二に、データを隠すことに加えて、データのカプセル化も向上させるようになり、複雑な宣言がより理解しやすくなることである。

もともとC言語の規格では、基本型(`int`などの組み込み型)のサイズや内部表現を厳密に規定しておらず、処理系依存となっている(ターゲット プラットフォームにとって都合の良いサイズや内部表現に設定してよいことになっている)ため、プラットフォーム間の違いを吸収して同じソースコードを使うためには`typedef`は必須の技術といえる。C99/C++11規格では、`int32_t`などのサイズや内部表現を保証する整数型が<stdint.h>/<cstdint>にて標準化されたが、これらは通例`typedef`シノニムを利用して実装される。とはいえ、エイリアスによる型定義は万能ではなく、汎整数拡張などのように組み込み型にまつわる問題は依然として残っている。

Microsoft WindowsにおけるWindows APIの例でいうと、Win16とWin32における`int`型の違いを吸収できる`INT32`型がエイリアス定義されている。また、Win16、Win32、Win64におけるポインタ互換整数型の違いを吸収できる`INT_PTR`型がエイリアス定義されている。

## 他の言語

Haskell、Miranda、Objective Caml等のような、多くの静的型付けの関数型言語では、C言語での`typedef`と同じ働きをする、type synonymを定義することができる。Haskellでの例を示す。

これにより、`Int`のペアと同じものをtype synonymの`PairOfInts`で定義することができる。

PascalおよびObject Pascalでは`type`キーワードを使用することで、`typedef`同様に別名を定義することができる。

C/C++の特徴を取り入れたC#言語では、基本型のサイズは厳密に決められており、また`typedef`は言語機能として存在しないが、代わりに`using`エイリアス ディレクティブ機能が存在する。

ジェネリクスを利用するときは特に型名が長大になりがちであり、ソースファイル中で何度も出現する場合にエイリアスを定義しておくと記述が楽になり、検索や置換も容易になる。

この`using`エイリアスは、ディレクティブが記述されたソースファイル内でのみ効果があるが、C# 10では`global`修飾子を付けることで、ソースファイルを超えてグローバルなエイリアスを定義できるようになった。