typedefと#defineの違い

5218 ワード

1.  typedef
typedef故名思意はタイプ定義の意味であるが、新しいタイプを定義するのではなく、既存のタイプに別名を付ける点では、参照の意味と同様に、参照は変数またはオブジェクトの別名であり、typedefはタイプの別名を定義する.typedefの役割は主に2つあります.
1.1複雑なタイプ宣言の簡略化
複雑なタイプ宣言を簡略化したり、既存のタイプに明確な別名を付けたりします.次のようになります.
typedef bool (*FuncPointer)(int, double);//boolタイプを返し、2つの(intとdouble)パラメータを持つ関数を返すポインタタイプFuncPointerを宣言します.
FuncPointer pFunc;//FuncPointerタイプの関数ポインタオブジェクトpFuncを宣言
1.2プラットフォームに関係のないタイプを定義する
プラットフォームに関係のないタイプを定義し、異なるプラットフォームのタイプの差異化を遮断する.次のようになります.
typedefを使用して、プラットフォームに関係のないタイプを定義します.
例えばREALという浮動小数点のタイプを定義し、目標プラットフォームにおいて、最高精度を表すタイプは以下の通りである.
typedef long double REAL;
long doubleをサポートしていないプラットフォーム2で、次のように変更します.
typedef double REAL;
doubleもサポートされていないプラットフォーム3で、次のように変更されました.
typedef float REAL;
すなわち、プラットフォームをまたぐ場合、typedef自体を変更すればよく、他のソースコードを変更する必要はありません.
標準ライブラリではsize_など、このテクニックが広く使われています.t.またtypedefは、単純な文字列置換ではなく、タイプを定義した新しい別名であるため、マクロよりも安定している.
1.3 structとの併用
C++では、structはclassと同じ役割を果たします.デフォルトのアクセス権が異なり、structはpublic、classはprivateがデフォルトです.
【例1.3.1】:
struct Person
{
	string name;
	int age;
	float height;
};
Person person;

StructのタイプPersonを定義し、Personのオブジェクトpersonを定義します.
または
struct Person
{
	string name;
	int age;
	float height;
}person;

StructのタイプPersonを定義し、定義と同時にPersonのオブジェクトpersonも宣言します.
 
しかしC言語ではstructの定義と宣言はtypedefを用いる.
【例1.3.2】:
typedef struct __Person
{
	string name;
	int age;
	float height;
}Person;	//  Person         
Person person;

typedefがなければstruct Person personを使わなければなりません.次のように宣言します.
【例1.3.3】
struct Person
{
	string name;
	int age;
	float height;
};
struct Person person;

または
struct Person
{
	string name;
	int age;
	float height;
}person;	//person Person   

 
2.typedefと#defineの違い
2.1.実行時間が異なる
キーワードtypedefはコンパイルフェーズで有効であり、コンパイルフェーズであるため、typedefにはタイプチェックの機能がある.
#defineはマクロ定義であり、前処理フェーズ、すなわちコンパイルの前に発生し、検査を行わずに単純で機械的な文字列置換のみを行う.
【例2.1.1】typedefは対応するタイプの検査を行う:
typedef unsigned int UINT;

void func()
{
	UINT value = "abc";	// error C2440: 'initializing' : cannot convert from 'const char [4]' to 'UINT'
	cout << value << endl;
}

【例2.1.2】#defineタイプチェックをしない:
//#define    :
#define f(x) x*x
int main()
{
	int a=6, b=2, c;
	c=f(a) / f(b);
	printf("%d
", c); return 0; }

プログラムの出力結果は:36であり、根本的な原因は#defineが単純な文字列置換であることにある.
 
2.2.機能に違いがある
typedefは、タイプの別名を定義したり、プラットフォームに関係のないデータ型を定義したり、structとの結合使用などに使用します.
#defineは、タイプに別名を付けるだけでなく、定数、変数、コンパイルスイッチなどを定義することもできます.
 
2.3.役割ドメインが違う
#defineは、役割ドメインの制限はありません.以前に定義されたマクロであれば、以降のプログラムで使用できます.
typedefには独自の役割ドメインがあります.
【例2.3.1】役割ドメインの制限はなく、先に定義されていればよい
void func1()
{
	#define HW "HelloWorld";
}

void func2()
{
	string str = HW;
	cout << str << endl;
}

【例2.3.2】typedefには独自の役割ドメインがある
void func1()
{
	typedef unsigned int UINT;
}

void func2()
{
	UINT uValue = 5;//error C2065: 'UINT' : undeclared identifier
}

【例2.3.3】
class A
{
	typedef unsigned int UINT;
	UINT valueA;
	A() : valueA(0){}
};

class B
{
	UINT valueB;
	//error C2146: syntax error : missing ';' before identifier 'valueB'
	//error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
};

上記の例では、クラスAの役割ドメインにのみ存在するため、BクラスでUINTを使用するとエラーが発生します.また、クラスでtypedefで定義されたタイプ別名には、対応するアクセス権限もあります.【例2.3.4】
class A
{
	typedef unsigned int UINT;
	UINT valueA;
	A() : valueA(0){}
};

void func3()
{
	A::UINT i = 1;
	// error C2248: 'A::UINT' : cannot access private typedef declared in class 'A'
}

UINTにpublicアクセス権を付与するとコンパイルできます.
【例2.3.5】:
class A
{
public:
	typedef unsigned int UINT;
	UINT valueA;
	A() : valueA(0){}
};

void func3()
{
	A::UINT i = 1;
	cout << i << endl;
}

 
2.4.ポインタの操作
両者がポインタタイプを修飾する場合、作用は異なります.
typedef int * pint;
#define PINT int *

int i1 = 1, i2 = 2;

const pint p1 = &i1;	//p    ,p         ,    int * const p;
const PINT p2 = &i2;	//p    ,p         ,    const int *p;  int const *p;

pint s1, s2;	//s1 s2  int   
PINT s3, s4;	//   int * s3,s4;       。

void TestPointer()
{
	cout << "p1:" << p1 << "  *p1:" << *p1 << endl;
	//p1 = &i2;	//error C3892: 'p1' : you cannot assign to a variable that is const
	*p1 = 5;
	cout << "p1:" << p1 << "  *p1:" << *p1 << endl;

	cout << "p2:" << p2 << "  *p2:" << *p2 << endl;
	//*p2 = 10;	//error C3892: 'p2' : you cannot assign to a variable that is const
	p2 = &i1;
	cout << "p2:" << p2 << "  *p2:" << *p2 << endl;
}

結果:
p1:00EFD094  *p1:1
p1:00EFD094  *p1:5
p2:00EFD098  *p2:2
p2:00EFD094  *p2:5
 
 
記事の参照と参照:
『typedefの使い方についてのまとめ』
『Typedefとdefineの違い』