1.typedef關鍵字
1.1簡單介紹
C語言允許使用者使用 typedef 關鍵字來定義自己習慣的數據型別名稱,來替代系統預設的基本型別名稱、陣列型別名稱、指針型別名稱與使用者自定義的結構型名稱、共用型名稱、列舉型名稱等。一旦使用者在程式中定義了自己的數據型別名稱,就可以在該程式中用自己的數據型別名稱來定義變數的型別、陣列的型別、指針變數的型別與函數的型別等。
1.2簡單用法
typedef的4種主要用法
1)爲基本數據型別定義新的型別名。有利於增強程式的可拓展性。
範例:
typedef long double REAL;
typedef unsigned int COUNT;
當跨平臺移植程式時,我們只需要修改一下 typedef 的定義即可,而不用對其他原始碼做任何修改。其實,標準庫中廣泛地使用了這個技巧,比如 size_t 在 VC++2010 的 crtdefs.h 檔案中的定義如下所示:
#ifndef _SIZE_T_DEFINED
#ifdef _WIN64
typedef unsigned __int64 size_t;
#else
typedef _W64 unsigned int size_t;
#endif
#define _SIZE_T_DEFINED
#endif
2)爲自定義數據型別(結構體、共用體和列舉型別)定義簡潔的型別名稱。
以結構體爲例,下面 下麪我們定義一個名爲 Game的結構體
struct Game
{
char * rule;
char * name;
int age;
};
在呼叫這個結構體時,我們必須像下面 下麪的程式碼這樣來呼叫這個結構體:
strucy Game game1 = {"man","tom",20};
在這裏,結構體 struct Game爲新的數據型別,在定義變數的時候均要向上面的呼叫方法一樣有保留字 struct,而不能像 int 和 double 那樣直接使用 Game 來定義變數。現在,我們利用 typedef 定義這個結構體,如下面 下麪的程式碼所示:
typedef struct itGame
{
char * rule;
char * name;
int age;
}Game;
在上面的程式碼中,實際上完成了兩個操作:
1)定義了一個新的結構體itGame
2)使用 typedef 爲這個新的結構起了一個別名,叫 Point,即:
typedef struct itGame Game;
但是typedef還是有坑的,例子如下:
在寫鏈表時經常有:
typedef struct tagNode
{
char *pItem;
pNode pNext;
} *pNode;
上面的範例程式碼與前面的定義方法相同,所以應該沒有什麼問題。但是編譯器卻報了一個錯誤,爲什麼呢?莫非 C 語言不允許在結構中包含指向它自己的指針?
其實是因爲:新結構建立的過程中遇到了 pNext 宣告,其型別是 pNode。這裏要特別注意的是,pNode 表示的是該結構體的新別名。於是問題出現了,在結構體型別本身還沒有建立完成的時候,編譯器根本就不認識 pNode,因爲這個結構體型別的新別名還不存在,所以自然就會報錯。因此,我們要做一些適當的調整,比如將結構體中的 pNext 宣告修改成如下方式:
typedef struct tagNode
{
char *pItem;
struct tagNode *pNext;
} *pNode;
3)爲陣列定義簡潔的型別名稱
例如:
typedef int int_Array[10];
int_Array arr;
4)爲指針定義簡潔的名稱
typedef char* PCHAR;
PCHAR arr;
適用於複雜型別的重新命名
int *(*a[5])(int,char*);
除此之外還有一點需要特別注意:
typedef char* PCHAR;
int strcmp(const PCHAR,const PCHAR);
這裏的「const PCHAR」 不是 「const char*」,而是char* const,因爲typedef修飾的是一個指針所以const也是一樣,此時const修飾的是一個指針並非所指的變數。
還需要特別注意的是,雖然 typedef 並不真正影響物件的儲存特性,但在語法上它還是一個儲存類的關鍵字,就像 auto、extern、static 和 register 等關鍵字一樣。
2.define關鍵字
2.1簡單介紹
C語言中,可以用 #define 定義一個識別符號來表示一個常數。其特點是:定義的識別符號不佔記憶體,只是一個臨時的符號,預處理後這個符號就不存在了。
用 #define 定義識別符號的一般形式爲:
#define 識別符號 常數
凡是以「#」開頭的均爲預處理指令,#define也不例外。//在預處理時都會被替換。
還有變數名錶示的是一個變數,但宏名錶示的是一個常數。可以給變數賦值,但絕不能給常數賦值。
2.2解決的問題
宏定義最大的好處是「方便程式的修改」。使用宏定義可以用宏代替一個在程式中經常使用的常數。注意,是「經常」使用的。這樣,當需要改變這個常數的值時,就不需要對整個程式一個一個進行修改,只需修改宏定義中的常數即可。且當常數比較長時,使用宏就可以用較短的有意義的識別符號來代替它,這樣程式設計的時候就會更方便,不容易出錯。因此,宏定義的優點就是方便和易於維護。
2.3注意
宏定義 #define 一般都寫在函數外面,與 #include 寫在一起。當然,寫在函數裏面也沒有語法錯誤,但通常不那麼寫。#define 的作用域爲自 #define 那一行起到源程式結束。如果要終止其作用域可以使用 #undef 命令,格式爲:
#undef
識別符號undef 後面的識別符號表示你所要終止的宏。比如前面在程式開頭用 define 定義了一個宏 M,它原本的作用範圍是一直到程式結束,但如果現在在程式中某個位置加了一句:
#undef 宏名
那麼這個宏的作用範圍到此就結束了。#undef 用得不多,但大家要瞭解。
2.3簡單範例
#define MAX 100
2.4特別注意的與typedef的不同
看以下程式碼:
#include<iostream>
#include<typeinfo>
using namespace std;
#define PIN1 int *
typedef int * PIN2;
int main()
{
PIN1 a,b;
cout<<"用define型別爲 "<<typeid(a).name()<<" "<<typeid(b).name()<<endl;
PIN2 c,d;
cout<<"用typedef型別爲 "<<typeid(c).name()<<" "<<typeid(d).name()<<endl;
return 0;
}
DEVC++輸出如下:
這裏先提一下怎麼檢視變數型別
使用typeinfo庫裡的typeid(變數).name()
如果想再瞭解可以檢視以下文章
c++檢視變數型別
在DECC++裡Pi我指針,i爲int型別
由上圖可知define與typedef的不同。