Typedeftypedef(タイプデフ)は、プログラミング言語のCおよびC++におけるキーワード(予約語)である。このキーワードはデータ型に新しい名前(エイリアス、シノニム)をつけるために使用される。プログラマが容易にソースコードを記述・理解できるようにすることが目的である。 使用例まず int is_even_number(int x) {
return x % 2 == 0;
}
この関数は入力 typedef int my_boolean_t;
my_boolean_t is_even_number(int x) {
return x % 2 == 0;
}
真偽値 (boolean) は通例0を偽、0以外を真とすることから、関数の仕様がより明確となっている[注釈 1]。サフィックス また、typedefは長大で複雑な型名を単純化するために用いられることもある。 typedef unsigned char byte;
typedef unsigned long long ulonglong;
byte vb = UCHAR_MAX;
ulonglong vull = ULLONG_MAX;
struct my_struct {
int data1;
int data2;
char data3;
};
ここでは、ユーザー定義の型 struct my_struct a;
my_struct b; /* 構文エラー */
ここで、構造体宣言の後に、以下の行を追加してみる。 typedef struct my_struct my_struct_t;
これにより、 my_struct_t a;
同じことは、以下のコードでも行うことができる。 typedef struct my_struct {
int data1;
int data2;
char data3;
} my_struct_t;
構造体のタグ名を省略することもできる。この場合、タグ名は処理系によって自動生成される。 typedef struct {
int data1;
int data2;
char data3;
} my_struct_t;
構造体のタグ名と別名を同一にすることもできる。 typedef struct my_struct_t {
int data1;
int data2;
char data3;
} my_struct_t;
以上の
typedef struct node_tag node_t;
struct node_tag {
node_t *nextptr;
int data;
};
通常、ある型のポインタ型変数を宣言する際、それぞれの変数名の前にアスタリスク node_t *startptr, *endptr, *curptr, *prevptr, errptr, *refptr;
プログラマは 新たに typedef node_t *node_ptr_t;
node_ptr_t startptr, endptr, curptr, prevptr, errptr, refptr;
これにより、 再代入や書き換えが不可能な文字列定数の配列(テーブル)を定義するときも、 #if 0
static const char *const planetNamesTable[] = { "Mercury", "Venus", "Earth", "Mars" };
#else
/* 以下は上記と等価。 */
typedef const char *ConstCharPtr;
static const ConstCharPtr planetNamesTable[] = { "Mercury", "Venus", "Earth", "Mars" };
#endif
関数へのポインタを利用する場合も #include <stdio.h>
/* 関数型のエイリアス */
typedef int binary_operator_t(int, int);
static int add(int a, int b) { return a + b; }
int main(int argc, char *argv[]) {
#if 0
int(*f)(int, int) = add;
#else
/* 以下は上記と同義だが、より簡潔かつ明瞭である。 */
binary_operator_t *f = add;
#endif
printf("add(12, 13) = %d\n", f(12, 13));
}
なお、上記は以下のようにも書ける。 #include <stdio.h>
/* 関数ポインタ型のエイリアス */
typedef int (*binary_operator_ptr_t)(int, int);
static int add(int a, int b) { return a + b; }
int main(int argc, char *argv[]) {
binary_operator_ptr_t f = add;
printf("add(12, 13) = %d\n", f(12, 13));
}
関数型もしくは関数ポインタ型のエイリアスを定義しておくと、特にコールバック関数へのポインタを引数として受け取る関数を定義するときに記述性や可読性が向上する。 配列に対して #include <stdio.h>
typedef int array_int_2_t[2];
int main(int argc, char *argv[]) {
array_int_2_t a;
a[0] = 12;
a[1] = 13;
printf("a[0] = %d, a[1] = %d\n", a[0], a[1]);
}
なお、以下のようなコードに対する動作は未定義となる。グローバルスコープを持ち、アンダースコア typedef struct _MyStruct {
...
} MyStruct;
マクロとの比較C/C++にはテキストの置換機能としてマクロも備わっているが、型名の置換に使うには問題がある。まず、ポインタ型を正しく扱えない。 #define const_char_ptr_t const char *
const_char_ptr_t s1 = "abc", s2 = "ABC"; // s2はconst char型となり、コンパイルエラーを引き起こす。
typedefであればポインタ型を正しく扱える。 typedef const char *const_char_ptr_t;
const_char_ptr_t s1 = "abc", s2 = "ABC";
また、マクロは乱暴な置換を行なうことから、意図しない置換による原因特定のしにくいコンパイルエラーを引き起こすこともある。 C++C言語と異なり、C++において構造体、共用体、列挙型、クラス型の変数を宣言する際は、 struct my_struct {
int data1;
int data2;
char data3;
};
という定義さえあれば、 my_struct a;
と宣言できる。 C++ではクラス(あるいは構造体)内部で C++のusingエイリアス宣言C++では typedef int MyInt; // intの別名MyIntの宣言
C++11では、上記は以下のようにも書ける。 using MyInt = int; // intの別名MyIntの宣言
なお、 template <typename T> using TStringMap = std::map<std::string, T>;
TStringMap<double> diametersTable = { { "Mercury", 4879 }, { "Venus", 12104 }, { "Earth", 12756 }, { "Mars", 6792 } };
批判と利点一部の人々は、 しかし、 もともとC言語の規格では、基本型( Microsoft WindowsにおけるWindows APIの例でいうと、Win16とWin32における 他の言語Haskell、Miranda、Objective Caml等のような、多くの静的型付けの関数型言語では、C言語での type PairOfInts = (Int, Int)
これにより、 PascalおよびObject Pascalでは type
TMyInt = Integer; // 組み込み型Integerに対するシノニム。
C/C++の特徴を取り入れたC#言語では、基本型のサイズは厳密に決められており、また using MyString = System.String;
ジェネリクスを利用するときは特に型名が長大になりがちであり、ソースファイル中で何度も出現する場合にエイリアスを定義しておくと記述が楽になり、検索や置換も容易になる。 using MyStringToDoubleDictionary = System.Collections.Generic.Dictionary<string, double>;
この 脚注注釈
出典
関連項目外部リンク
|
Portal di Ensiklopedia Dunia