[ 定義 ]
一個變數,用來存放變數位址。
[ 宣告方式 ]
1.
int i = 100;
int *ptr = &i; //宣告ptr為指標,存入i的位址
2.
int i = 100;
int * ptr; //宣告ptr為指標
ptr = &i; //存入i的位址。不可以寫成*ptr = &i
函式型態的別名:
很多寫 C/C++ 的人都把 typedef 當成#define 來使用。
誠然,像這樣的定義
typedef unsigned short WORD;
就相當於
#define WORD unsigned short
但就本義來說,#define 是字串的取代,例如
#define WORD Hello!
在程式任何使用到 WORD 的地方會用 Hello! 取代 WORD
typedef看來不怎麼有用是吧!?非也,由於所謂 C/C++ 的型態是很廣義的,使用typedef
可以使程式看起來簡潔易懂且不容易出錯。下面是幾個typedef的應用例子:
簡單型態的別名
typedef unsigned char BYTE;//定義無號單字節的型態
typedef unsigned short WORD;//定義無號雙字節的型態
typedef unsigned long DWORD;//定義無號四字節的型態
//嗯!這三行沒什麼大不了,用#define也可以做
結構型態的別名
typedef struct StructTag{
int mA;
int mB;
}STRUCTTAG, *PSTRUCTTAG;
當要建立這個結構的物件時,就可以用別名 STRUCTTAG 和 PSTRUCTTAG,例如
STRUCTTAG StructObj;
PSTRUCTTAG pStructObj;
就相當於
struct StructTag StructObj;
struct StructTag *pStructObj;
函式型態的別名
如果你有一個 library 提供了字串轉整數的函式
int HexToInt(char *str);//十六進位字串轉整數
int DecToInt(char *str);//十進位字串轉整數
當你的程式要使用這些函式時,就必需include這些函式的定義,但用typedef會
更簡潔:
typedef int ToInt(char *str);
//上面這行定義了一個需傳入字串(char *)且返回整數(int)的函式型態別名
//叫 ToInt
ToInt HexToInt,DecToInt;//宣告HexToInt,DecToInt這兩個函式
現在你的程式可以呼叫HexToInt(...),DecToInt(...)了。
在Windows,通常是應用程式呼叫API來工作的,但由於某種需求,Windows API
會反過來呼叫應用程式的函式,這種函式稱之為 callback function。
callback function 對API來說只有該傳入那些參數和返回值型態,沒有函式名稱而用函式
指標來呼叫(事實上Windows也不可能用程式的函式名稱來呼叫)。這時使用函式型態的別名
來宣告函式指標就特別好用了。
舉個例子吧!建立一個新的行程(Thread)的函式:
CWinThread* AfxBeginThread( AFX_THREADPROC pfnThreadProc,
LPVOID pParam, int nPriority = THREAD_PRIORITY_NORMAL, UINT
nStackSize = 0, DWORD dwCreateFlags = 0,
LPSECURITY_ATTRIBUTES lpSecurityAttrs = NULL );
其中AFX_THREADPROC就是一個函式型態的別名
它的定義是
typedef UINT (AFX_CDECL *AFX_THREADPROC)(LPVOID);
//AFX_THREADPROC 是一個傳入一個指標參數返回UINT型態值的函式
//指標的名稱(AFX_CDEL是標明函式呼叫為 __cdecl(C style calling convention))
用這個宣告,不論API或應用程式本身都很方便,如應用程式可以這樣來
開啟行程:
CWinThread* pMyThread=AfxBeginThread(
(AFX_THREADPROC)MyThreadFunc,............
是不是很簡潔明瞭?嗯...MyThreadFunc算不算 callback function 有點疑義,但做為 typedef 的使用例子應沒問題的
typedef :
將資料型態定義成自己希望的識別字,方便撰寫程式.
比方說
typedef int number; // 表示number識別字和int相同.
int n; // 宣告一個int變數n.
number n; // 宣告一個number變數n,而number其實就是int.
又比方說有一個結構叫做record
struct record
{
int number;
struct record *next;
}
typedef struct record Node; // 表示Node識別字和struct record相同.
struct record record1; // 宣告一個record結構名為record1.
Node record1; // 宣告一個Node 結構名為record1,而Node 其實就是 struct record的意思.
除了省下了打字的力氣以外,由於不同的機器使用的資料型態都不太一樣,換機器跑程式時,只要修改typedef就好了,增加了C的可攜性.
[ 參考 ] http://home.educities.edu.tw/peterhuang1/Clan/CLanTypedef.htm
2.
struct t_Point
{
int x; int y;
}; // 注意,這裡最後一個分號不能省略
int main(int argc, char* argv[])
{
struct t_Point a, b;
// . . .
return 0;
}
顯然,這種方法沒有typedef更加直觀(在C++中,main函數第一行的struct關鍵字可以省略,但在標準C中,省略該關鍵字會出現編譯錯誤)。
此外,對於定義鏈接隊列中的結點,我們可以這樣實現:
typedef struct t_node
{
int Value;
struct t_node *next;
} Node;
當然也可以這樣定義:
typedef strcut t_node Node;
struct t_node
{
int Value;
Node *next;
};
比方說
typedef int number; // 表示number識別字和int相同.
int n; // 宣告一個int變數n.
number n; // 宣告一個number變數n,而number其實就是int.
又比方說有一個結構叫做record
struct record
{
int number;
struct record *next;
}
typedef struct record Node; // 表示Node識別字和struct record相同.
struct record record1; // 宣告一個record結構名為record1.
Node record1; // 宣告一個Node 結構名為record1,而Node 其實就是 struct record的意思.
除了省下了打字的力氣以外,由於不同的機器使用的資料型態都不太一樣,換機器跑程式時,只要修改typedef就好了,增加了C的可攜性.
[ 參考 ] http://home.educities.edu.tw/peterhuang1/Clan/CLanTypedef.htm
2.
struct t_Point
{
int x; int y;
}; // 注意,這裡最後一個分號不能省略
int main(int argc, char* argv[])
{
struct t_Point a, b;
// . . .
return 0;
}
顯然,這種方法沒有typedef更加直觀(在C++中,main函數第一行的struct關鍵字可以省略,但在標準C中,省略該關鍵字會出現編譯錯誤)。
此外,對於定義鏈接隊列中的結點,我們可以這樣實現:
typedef struct t_node
{
int Value;
struct t_node *next;
} Node;
當然也可以這樣定義:
typedef strcut t_node Node;
struct t_node
{
int Value;
Node *next;
};
結構中的冒號; 位域 :
位域
有些信息在存儲時,並不需要佔用一個完整的字節, 而只需占幾個或一個二進制位。例如在存放一個開關量時,只有0和1 兩種狀態, 用一位二進位即可。為了節省存儲空間,並使處理簡便,C語言又提供了一種數據結構,稱為「位域」或「位段」。所謂「位域」是把一個字節中的二進位劃分為幾個不同的區域, 並說明每個區域的位數。每個域有一個域名,允許在程序中按域名進行操作。 這樣就可以把幾個不同的對象用一個字節的二進制位域來表示。一、位域的定義和位域變量的說明位域定義與結構定義相仿,其形式為:
struct 位域結構名
{ 位域列表 };
其中位域列表的形式為: 類型說明符 位域名:位域長度
例如:
struct bs
{
int a:8;
int b:2;
int c:6;
};
位域變量的說明與結構變量說明的方式相同。 可採用先定義後說明,同時定義說明或者直接說明這三種方式。例如:
struct bs
{
int a:8;
int b:2;
int c:6;
}data;
說明data為bs變量,共佔兩個字節。其中位域a占8位,位域b占2位,位域c占6位。對於位域的定義尚有以下幾點說明:
1. 一個位域必須存儲在同一個字節中,不能跨兩個字節。如一個字節所剩空間不夠存放另一位域時,應從下一單元起存放該位域。也可以有意使某位域從下一單元開始。例如:
struct bs
{
unsigned a:4
unsigned :0 /*空域*/ unsigned b:4 /*從下一單元開始存放*/
unsigned c:4
}
在這個位域定義中,a佔第一字節的4位,後4位填0表示不使用,b從第二字節開始,佔用4位,c佔用4位。
2. 由於位域不允許跨兩個字節,因此位域的長度不能大於一個字節的長度,也就是說不能超過8位二進位。
3. 位域可以無位域名,這時它只用來作填充或調整位置。無名的位域是不能使用的。例如:
struct k
{
int a:1
int :2 /*該2位不能使用*/ int b:3
int c:2
};
從以上分析可以看出,位域在本質上就是一種結構類型, 不過其成員是按二進位分配的。
二、位域的使用
位域的使用和結構成員的使用相同,其一般形式為: 位域變量名·位域名 位域允許用各種格式輸出。
main(){
struct bs
{
unsigned a:1;
unsigned b:3;
unsigned c:4;
} bit,*PBit;
bit.a=1;
bit.b=7;
bit.c=15;
printf("%d,%d,%d\n",bit.a,bit.b,bit.c);
PBit=&bit;
PBit->a=0;
PBit->b&=3;
PBit->c=1;
printf("%d,%d,%d\n",PBit->a,PBit->b,PBit->c);
}
上例程序中定義了位域結構bs,三個位域為a,b,c。說明了bs類型的變量bit和指向bs類型的指針變量PBit。這表示位域也是可以使用指標的。
程序的9、10、11三行分別給三個位域賦值。( 應注意賦值不能超過該位域的允許範圍)程序第12行以整型量格式輸出三個域的內容。第13行把位域變量bit的地址送給指針變量PBit。第14行用指針方式給位域a重新賦值,賦為0。第15行使用了復合的位運算符"&=", 該行相當於: PBit->b=PBit->b&3位域b中原有值為7,與3作按位與運算的結果為3(111&011=011,十進制值為3)。同樣,程序第16行中使用了復合位運算"=", 相當於: PBit->c=PBit->c1其結果為15。程序第17行用指針方式輸出了這三個域的值。
有些信息在存儲時,並不需要佔用一個完整的字節, 而只需占幾個或一個二進制位。例如在存放一個開關量時,只有0和1 兩種狀態, 用一位二進位即可。為了節省存儲空間,並使處理簡便,C語言又提供了一種數據結構,稱為「位域」或「位段」。所謂「位域」是把一個字節中的二進位劃分為幾個不同的區域, 並說明每個區域的位數。每個域有一個域名,允許在程序中按域名進行操作。 這樣就可以把幾個不同的對象用一個字節的二進制位域來表示。一、位域的定義和位域變量的說明位域定義與結構定義相仿,其形式為:
struct 位域結構名
{ 位域列表 };
其中位域列表的形式為: 類型說明符 位域名:位域長度
例如:
struct bs
{
int a:8;
int b:2;
int c:6;
};
位域變量的說明與結構變量說明的方式相同。 可採用先定義後說明,同時定義說明或者直接說明這三種方式。例如:
struct bs
{
int a:8;
int b:2;
int c:6;
}data;
說明data為bs變量,共佔兩個字節。其中位域a占8位,位域b占2位,位域c占6位。對於位域的定義尚有以下幾點說明:
1. 一個位域必須存儲在同一個字節中,不能跨兩個字節。如一個字節所剩空間不夠存放另一位域時,應從下一單元起存放該位域。也可以有意使某位域從下一單元開始。例如:
struct bs
{
unsigned a:4
unsigned :0 /*空域*/ unsigned b:4 /*從下一單元開始存放*/
unsigned c:4
}
在這個位域定義中,a佔第一字節的4位,後4位填0表示不使用,b從第二字節開始,佔用4位,c佔用4位。
2. 由於位域不允許跨兩個字節,因此位域的長度不能大於一個字節的長度,也就是說不能超過8位二進位。
3. 位域可以無位域名,這時它只用來作填充或調整位置。無名的位域是不能使用的。例如:
struct k
{
int a:1
int :2 /*該2位不能使用*/ int b:3
int c:2
};
從以上分析可以看出,位域在本質上就是一種結構類型, 不過其成員是按二進位分配的。
二、位域的使用
位域的使用和結構成員的使用相同,其一般形式為: 位域變量名·位域名 位域允許用各種格式輸出。
main(){
struct bs
{
unsigned a:1;
unsigned b:3;
unsigned c:4;
} bit,*PBit;
bit.a=1;
bit.b=7;
bit.c=15;
printf("%d,%d,%d\n",bit.a,bit.b,bit.c);
PBit=&bit;
PBit->a=0;
PBit->b&=3;
PBit->c=1;
printf("%d,%d,%d\n",PBit->a,PBit->b,PBit->c);
}
上例程序中定義了位域結構bs,三個位域為a,b,c。說明了bs類型的變量bit和指向bs類型的指針變量PBit。這表示位域也是可以使用指標的。
程序的9、10、11三行分別給三個位域賦值。( 應注意賦值不能超過該位域的允許範圍)程序第12行以整型量格式輸出三個域的內容。第13行把位域變量bit的地址送給指針變量PBit。第14行用指針方式給位域a重新賦值,賦為0。第15行使用了復合的位運算符"&=", 該行相當於: PBit->b=PBit->b&3位域b中原有值為7,與3作按位與運算的結果為3(111&011=011,十進制值為3)。同樣,程序第16行中使用了復合位運算"=", 相當於: PBit->c=PBit->c1其結果為15。程序第17行用指針方式輸出了這三個域的值。
沒有留言:
張貼留言