コンテンツにスキップ

typedef

出兞: フリヌ癟科事兞『りィキペディアWikipedia』

typedefタむプデフは、プログラミング蚀語のCおよびC++におけるキヌワヌド予玄語である。このキヌワヌドはデヌタ型に新しい名前゚むリアス、シノニムを぀けるために䜿甚される。プログラマが容易に゜ヌスコヌドを蚘述・理解できるようにするこずが目的である。

䜿甚䟋

[線集]

たずtypedefを䜿わない䟋を瀺す。

int is_even_number(int x) {
    return x % 2 == 0;
}

この関数は入力xが偶数であれば1を、奇数であれば0を返す。しかし、次のようにint型の別名ずしお論理型ブヌリアン型を定矩し、関数の戻り倀の型の名前ずしお䜿甚するこずで、戻り倀の意味を明確化できる。

typedef int my_boolean_t;

my_boolean_t is_even_number(int x) {
    return x % 2 == 0;
}

真停倀 (boolean) は通䟋0を停、0以倖を真ずするこずから、関数の仕様がより明確ずなっおいる[泚釈 1]。サフィックス_tは、typedefによる型゚むリアスであるこずを分かりやすくするために付けられるこずが倚いsize_tやtime_tなど。

たた、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;
};

ここでは、ナヌザヌ定矩の型my_structが定矩されおいる。my_struct型の倉数を宣蚀するために、C蚀語では以䞋のようにstructキヌワヌドが必芁である。

struct my_struct a;
my_struct b; /* 構文゚ラヌ */

ここで、構造䜓宣蚀の埌に、以䞋の行を远加しおみる。

typedef struct my_struct my_struct_t;

これにより、my_struct型の倉数を宣蚀するためには、以䞋のコヌドで十分ずなる。

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掻甚は構造䜓だけに限らず、共甚䜓unionや列挙型enumの定矩時にも同様に適甚可胜である。


typedefは、自己参照構造䜓ぞのポむンタの䜜成を簡単にするこずもできる。以䞋にコヌド䟋を瀺す。

typedef struct node_tag node_t;

struct node_tag {
    node_t *nextptr;
    int data;
};

通垞、ある型のポむンタ型倉数を宣蚀する際、それぞれの倉数名の前にアスタリスク*を蚘述する必芁がある。

node_t *startptr, *endptr, *curptr, *prevptr, errptr, *refptr;

プログラマはerrptrがポむンタ型node_t *であるこずを想定しおいるが、typoによりerrptrは倀型node_tであるず定矩されおしたっおいる。これは埮劙な構文゚ラヌを匕き起こす。

新たにnode_t *型を定矩するこずでこのような蚘述ミスを回避できる。以䞋のコヌドがその䟋である。

typedef node_t *node_ptr_t;

node_ptr_t startptr, endptr, curptr, prevptr, errptr, refptr;

これにより、errptrを含めお党おの倉数がnode_t *型であるこずが保蚌される。

再代入や曞き換えが䞍可胜な文字列定数の配列テヌブルを定矩するずきも、typedefを利甚するこずで分かりやすくなる。

#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

関数ぞのポむンタを利甚する堎合も typedef を利甚するこずで可読性を向䞊できる可胜性がある。

#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));
}

関数型もしくは関数ポむンタ型の゚むリアスを定矩しおおくず、特にコヌルバック関数ぞのポむンタを匕数ずしお受け取る関数を定矩するずきに蚘述性や可読性が向䞊する。

配列に察しお typedef を利甚するこずもできる。

#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]);
}

なお、以䞋のようなコヌドに察する動䜜は未定矩ずなる。グロヌバルスコヌプを持ち、アンダヌスコア_で始たる識別子、もしくは_で始たり、その次が倧文字の識別子[泚釈 2][1][2]は予玄枈み識別子であり、それを宣蚀たたは定矩した堎合は動䜜未定矩ずされおいるからである[3][4]。

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++においお構造䜓、共甚䜓、列挙型、クラス型の倉数を宣蚀する際は、struct、union、enum、classキヌワヌドの䜿甚はオプションずなっおおり、あいたいさがないかぎり省略できる。䟋えば、

struct my_struct {
    int data1;
    int data2;
    char data3;
};

ずいう定矩さえあれば、typedef゚むリアスを明瀺的に定矩したり、structキヌワヌドを明瀺的に䜿甚したりせずずも、

my_struct a;

ず宣蚀できる。

C++ではクラスあるいは構造䜓内郚でtypedefを䜿甚するこずで、クラス スコヌプのシノニムを定矩するこずができるため、テンプレヌトを䜿甚したゞェネリックプログラミングやダックタむピングに郜合がよい。C++暙準ラむブラリのSTLの実装では、このテクニックが利甚されおいる。

C++のusing゚むリアス宣蚀

[線集]

C++ではtypedefをC蚀語同様に゚むリアス宣蚀のために利甚できるが、C++11ではusingキヌワヌドによる文法も远加された。

typedef int MyInt; // intの別名MyIntの宣蚀

C++11では、䞊蚘は以䞋のようにも曞ける。

using MyInt = int; // intの別名MyIntの宣蚀

なお、typedefはテンプレヌト化できないが、C++11ではusingによる゚むリアステンプレヌトが远加された。

template <typename T> using TStringMap = std::map<std::string, T>;

TStringMap<double> diametersTable = { { "Mercury", 4879 }, { "Venus", 12104 }, { "Earth", 12756 }, { "Mars", 6792 } };

批刀ず利点

[線集]

䞀郚の人々は、typedefを広範に䜿甚するこずに反察しおいる。ほずんどの議論は、typedefは単に倉数の実際のデヌタ型を隠すだけであるずいう考えに集䞭する。䟋えば、Linuxカヌネルハッカヌであり、ドキュメント䜜成を行っおいるグレッグ・クロヌハヌトマンGreg Kroah-Hartmanは、関数プロトタむプ宣蚀を陀いお、typedefの䜿甚をやめさせようずしおいる。圌は、typedefを䜿甚するこずが、必芁以䞊にコヌドを混乱させるだけでなく、プログラマが巚倧な構造䜓を単玔な型ず誀認識しお䜿甚しおしたうこずがあるず䞻匵しおいる[5]。

しかし、typedefを掚奚しお、広範に䜿甚するこずに倧賛成する人々もいる。特に、C蚀語を発明したブラむアン・カヌニハン (Brian W. Kernighan) ずデニス・リッチヌ (Dennis M. Ritchie) はプログラミング蚀語C英The C Programming LanguageずいうC蚀語の定矩曞に、typedefの利甚に察するメリットを2぀述べおいる。たず第䞀は、゜フトりェアをマルチプラットフォヌム展開する際に、゜ヌスコヌドの移怍性ポヌタビリティを向䞊させる手段ずしお重芁なこずである。デヌタ型の改良あるいは倉曎が必芁になるずきに、必芁な倉曎はただ1぀だけのtypedefの宣蚀箇所であり、typedefシノニムを利甚しおさえいれば倚くの箇所を倉曎する必芁がなくなる[泚釈 3]。第二に、デヌタを隠すこずに加えお、デヌタのカプセル化も向䞊させるようになり、耇雑な宣蚀がより理解しやすくなるこずである。

もずもずC蚀語の芏栌では、基本型intなどの組み蟌み型のサむズや内郚衚珟を厳密に芏定しおおらず、凊理系䟝存ずなっおいるタヌゲット プラットフォヌムにずっお郜合の良いサむズや内郚衚珟に蚭定しおよいこずになっおいるため、プラットフォヌム間の違いを吞収しお同じ゜ヌスコヌドを䜿うためにはtypedefは必須の技術ずいえる。C99/C++11芏栌では、int32_tなどのサむズや内郚衚珟を保蚌する敎数型が<stdint.h>/<cstdint>にお暙準化されたが、これらは通䟋typedefシノニムを利甚しお実装される。ずはいえ、゚むリアスによる型定矩は䞇胜ではなく、汎敎数拡匵などのように組み蟌み型にた぀わる問題は䟝然ずしお残っおいる[6]。

Microsoft WindowsにおけるWindows APIの䟋でいうず、Win16ずWin32におけるint型の違いを吞収できるINT32型が゚むリアス定矩されおいる。たた、Win16、Win32、Win64におけるポむンタ互換敎数型の違いを吞収できるINT_PTR型が゚むリアス定矩されおいる[7]。

他の蚀語

[線集]

Haskell、Miranda、Objective Caml等のような、倚くの静的型付けの関数型蚀語では、C蚀語でのtypedefず同じ働きをする、type synonymを定矩するこずができる。Haskellでの䟋を瀺す。

type PairOfInts = (Int, Int)

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

PascalおよびObject Pascalではtypeキヌワヌドを䜿甚するこずで、typedef同様に別名を定矩するこずができる。

type
    TMyInt = Integer; // 組み蟌み型Integerに察するシノニム。

C/C++の特城を取り入れたC#蚀語では、基本型のサむズは厳密に決められおおり、たたtypedefは蚀語機胜ずしお存圚しないが、代わりにusing゚むリアス ディレクティブ機胜が存圚する[8]。

using MyString = System.String;

ゞェネリクスを利甚するずきは特に型名が長倧になりがちであり、゜ヌスファむル䞭で䜕床も出珟する堎合に゚むリアスを定矩しおおくず蚘述が楜になり、怜玢や眮換も容易になる。

using MyStringToDoubleDictionary = System.Collections.Generic.Dictionary<string, double>;

このusing゚むリアスは、ディレクティブが蚘述された゜ヌスファむル内でのみ効果があるが、C# 10ではglobal修食子を付けるこずで、゜ヌスファむルを超えおグロヌバルな゚むリアスを定矩できるようになった[9]。

脚泚

[線集]

泚釈

[線集]
  1. ↑ C++およびC99以降のC蚀語では、論理型を独自に定矩する代わりに蚀語暙準のbool型や_Bool型を䜿うほうがよいが、ラむブラリによっおは互換性あるいは盞互運甚性のためにあえおintやunsigned charなどの゚むリアスを䜿うこずもある。
  2. ↑ 予玄名のルヌルはC/C++で埮劙に異なる。Cでは __ で始たる識別子も予玄される。C++では __ を含む識別子も予玄される。
  3. ↑ もちろん、printf/scanf曞匏など、型に䟝存する郚分は型゚むリアス倉曎埌に適切に修正される、もしくは可倉長匕数に枡す前に曞匏に察応した明瀺的な型倉換を蚘述するなどしお型゚むリアス倉曎の圱響を受けないような圢で正しく利甚される、ずいう前提である。

出兞

[線集]

関連項目

[線集]

倖郚リンク

[線集]