一、typedef的用法 1.用typedef來聲明新的類型名,來代替已有的類型名,也就是給類型起別名。比如 這種用法經常用來作為定義與平臺無關的類型,方便代碼的跨平臺移植。 例如,定義REAL類型為目標平臺精度最高的類型。 1>在支持long double的平臺上定義為: 註:long doubl ...
一、typedef的用法
1.用typedef來聲明新的類型名,來代替已有的類型名,也就是給類型起別名。比如
1 typedef float REAL; //用REAL來代表float類型 2 REAL a; //定義一個REAL類型的變數,等價於float a,即定義一個float類型的變數a
這種用法經常用來作為定義與平臺無關的類型,方便代碼的跨平臺移植。
例如,定義REAL類型為目標平臺精度最高的類型。
1>在支持long double的平臺上定義為:
typedef long double REAL;
註:long double為C99增加的類型,ANSI C標準規定了double變數存儲為 IEEE 64 位(8 個位元組)浮點數值,但並未規定long double的確切精度,但規定long double的精度不少於double的精度。所以對於不同平臺long double可能有不同的實現,有的是8位元組,有的是10位元組,有的是12位元組或16位元組。關於具體的編譯器的情況, 可以通過 sizeof(long double)得知。
2>在不支持long double的平臺上改為
typedef double REAL;
3>在double不支持的平臺上改為
typedef float REAL;
因此,當跨平臺時,只要改下 typedef 本身就行,不用對其他源碼做任何修改。
2.為自定義數據結構(如struct、union)定義簡潔易記的類型名。
比如:
struct data{ int month; int day; int year; }; //定義一個data的結構體
聲明結構體變數時,代碼如下
struct data birthday;
用typedef可以定義新的類型,代替上面的結構體類型
typedef struct data{ int month; int day; int year; }DATA; //定義一個data的結構體 DATA birthday; //定義一個DATA類型的變數birthday,等價於上面struct data類型
註:這種方法在一些代碼規範中是不推薦和禁止的,因為新的類型隱藏了具體的類型,不利於看代碼的人直觀瞭解到實際類型。
3.用typedef來聲明新的類型
1>可以用來簡化數組變數定義
typedef int ARR[10]; //定義類型ARR為含有10個元素的int數組 ARR arr_a, arr_b; //定義了兩個含有10個元素的int數組變數arr_a,arr_b
2>簡化指針變數的定義
typedef int* INT_P INT_P p1,p2; //定義兩個int指針變數p1、p2
註意,下麵的定義容易引起錯誤,所以編程規範中禁止一次聲明多個變數
int* p1, p2; //p1為int*類型,p2為int類型
1 typedef char* STRING; 2 STRINT p; //p為字元串指針變數 3 STRINT s[10]; //s為指針數組,即s為一個含有10個元素的數組,每個元素是一個字元串指針 4 5 typedef int (* POINTER)(); //聲明POINTTER為指向函數的指針類型,該函數返回值為int類型 6 POINTER p1,p2; //p1,p2均為函數指針變數;
4.為複雜的聲明定義一個新的簡單的別名。
int *(*a[5])(int, char*); //變數名為a,直接用一個新別名pFun替換a typedef int *(*pFun)(int, char*); pFun a[5]; //定義一個含有5個函數指針的數組
void (*b[10]) (void (*)()); //原聲明,b為含有10個元素的函數指針數組,其參數為不帶參數的函數指針 typedef void (*pFunParam)();//聲明不帶參數的函數指針為類型pFunParam typedef void (*pFunx)(pFunParam); //聲明pFunx為函數指針 pFunx b[10]; //函數指針數組b
1 doube(*)() (*e)[9]; //變數e為指針,該指針指向一個數組,該數組含有9個元素,每個元素為一個函數指針,該函數指針的返回值為double類型 2 簡化寫法: 3 typedef double(*pFuny)(); //聲明一個函數指針別名pFuny,返回類型為double 4 typedef pFuny (*pFunParamy)[9]; //聲明一個指針 5 pFunParamy e;//聲明變數e為pFunParamy類型
理解複雜聲明可用的“右左法則”:
從變數名看起,先往右,再往左,碰到一個圓括弧就調轉閱讀的方向;括弧內分析完就跳出括弧,還是按先右後左的順序,如此迴圈,直到整個聲明分析完。舉例:
int (*func)(int *p);
首先找到變數名func,外面有一對圓括弧,而且左邊是一個*號,這說明func是一個指針;然後跳出這個圓括弧,先看右邊,又遇到圓括弧,這說明(*func)是一個函數,所以func是一個指向這類函數的指針,即函數指針,這類函數具有int*類型的形參,返回值類型是int。
int (*func[5])(int *);
func右邊是一個[]運算符,說明func是具有5個元素的數組;func的左邊有一個*,說明func的元素是指針(註意這裡的*不是修飾func,而是修飾func[5]的,原因是[]運算符優先順序比*高,func先跟[]結合)。跳出這個括弧,看右邊,又遇到圓括弧,說明func數組的元素是函數類型的指針,它指向的函數具有int*類型的形參,返回值類型為int。
也可以記住2個模式:
type (*)(....)函數指針
type (*)[]數組指針
二、typedef的陷阱
1.typedef是一種新類型的聲明,不是簡單的字元串替換,不同於#define
例如:
1 typedef char* STRING; 2 int strcmp(const STRING,const STRING);
在上面的代碼中,“const STRING” 是否相當於 “const char*” 呢?
答案是否定的,原因很簡單,typedef 是用來聲明一種新的類型,它不同於巨集,不是簡單的字元串替換。STRING已經是一種類型,const修改該類型為常量。因此,“const STRING”中的 const 給予了STRING常量屬性,也就是整個指針本身常量性,也即形成了常量指針“char*const(一個指向char的常量指針)”。
即它實際上相當於“char*const”,而不是“const char*(指向常量 char 的指針)”。當然,要想讓 const PCHAR 相當於 const char* 也很容易,如下麵的代碼所示:
typedef const char* PCHAR; int strcmp(PCHAR, PCHAR);
因此,無論什麼時候,只要為指針聲明 typedef,那麼就應該在最終的 typedef 名稱中加一個 const,以使得該指針本身是常量。
2.typedef 和存儲類關鍵字(storage class specifier)
typedef在語法上是一個存儲類的關鍵字(如auto、extern、mutable、static、register等一樣),雖然它並不真正影響對象的存儲特性。
例如下麵的代碼會編譯報錯:
1 typedef static int INT_STATIC;
參考:
https://www.cnblogs.com/a-s-m/p/10995722.html
http://c.biancheng.net/view/298.html