#define、typedef用法


一、#define

1.簡單的define定義 

1 #define MAXTIME 1000

這樣的定義看起來類似於普通的常量定義CONST,但也有着不同,因為define的定義更像是簡單的文本替換,而不是作為一個量來使用,這個問題在下面反映的尤為突出。

2.define的“函數定義”

define可以像函數那樣接受一些參數,如下

 1 #define  max(x,y)  (x)>(y)?(x):(y); 

定義就將返回兩個數中較大的那個。因為這個“函數”沒有類型檢查,就好像一個函數模板似的,當然,它絕對沒有模板那么安全就是了。可以作為一個簡單的模板來使用而已。

但是這樣做的話存在隱患,例子如下:

 1 #define Add(a,b) a+b; 

如果遇到如:c * Add(a,b) * d的時候就會出現問題,代數式的本意是a+b然后去和c,d相乘,但是因為使用了define,所以式子實際上變成了c*a + b*d

3.宏的單行定義

1 #define A(x)  T_##x
2 #define B(x)  #@x
3 #define C(x)  #x

我們假設:x=1,則有:

A(1)------〉T_1

B(1)------〉'1'

C(1)------〉"1"

4.define的多行定義

define可以替代多行的代碼,例如MFC中的宏定義(非常的經典,雖然讓人看了惡心)

1 #define MACRO(arg1, arg2) do { /
2 /* declarations */ /
3 stmt1; /
4 stmt2; /
5 /* ... */ /
6 } while(0) /* (no trailing ; ) */

關鍵是要在每一個換行的時候加上一個"/"

5.在大規模的開發過程中,特別是跨平台和系統的軟件里,define 最重要的功能是條件編譯。

就是:

1 #ifdef WINDOWS
2 ......
3 #endif
4 #ifdef LINUX
5 ......
6 #endif

可以在編譯的時候通過#define設置編譯環境

6.如何定義宏、取消宏

1 //定義宏
2 #define [MacroName] [MacroValue]
3 //取消宏
4 #undef  [MacroName]
5 //普通宏
6 #define PI (3.1415926)
1 //帶參數的宏
2 #define max(a,b) ((a)>(b)? (a),(b))

7.條件編譯

1 #ifdef XXX…(#else) …
2 #endif
3 #ifdef DV22_AUX_INPUT
4 #define AUX_MODE 3
5 #else
6 #define AUY_MODE 3
7 #endif
8 #ifndef XXX … (#else) … 
9 #endif

8.頭文件(.h)可以被頭文件或C文件包含

重復包含(重復定義)

由於頭文件包含可以嵌套,那么C文件就有可能包含多次同一個頭文件,就可能出現重復定義的問題的。

通過條件編譯開關來避免重復包含(重復定義)

例如

1 #ifndef __headerfileXXX__
2 #define __headerfileXXX__
3 4 //文件內容
5 6 #endif

9. #define中的#、## && #@ 

前些一段時間在看WinCE的Code時發現在宏定義中有用到##,如下所示

1 #define GPEBLT_FUNCNAME(basename) (SCODE (GPE::*)(struct GPEBltParms *))&GPE::##basename

在#define中,標准只定義了#和##兩種操作。#用來把參數轉換成字符串,##則用來連接兩個前后兩個參數,把它們變成一個字符串。 

1 #define ToString(a) #a
2 ToString( A b Cd ); //A b Cd
3 ToString( A/n b Cd ); //A
4  // b Cd
5 ToString( A/ n b Cd ); //A n b Cd

另外,在網上搜到還有一種用法:#@,把參數轉換成字符

1 #define ToChar(a) #@a
2 ToChar(a); // a
3 ToChar(ab); // b
4 ToChar(abc); // c
5 ToChar(abcd); // d
6 //ToChar(abcde); // too many characters in constant
7 ToChar(1.); // .

二、typedef

用途一:定義一種類型的別名,而不只是簡單的宏替換。可以用作同時聲明指針型的多個對象。

比如:

1 char* pa, pb; // 這多數不符合我們的意圖,它只聲明了一個指向字符變量的指針,和一個字符變量;
2 typedef char* PCHAR;
3 PCHAR pa, pb;  

這種用法很有用,特別是char* pa, pb的定義,初學者往往認為是定義了兩個字符型指針,其實不是,而用typedef char* PCHAR就不會出現這樣的問題,減少了錯誤的發生。

用途二:用在舊的C代碼中,幫助struct。

以前的代碼中,聲明struct新對象時,必須要帶上struct,即形式為: struct 結構名對象名,如:

1 struct tagPOINT1
2  {
3     int x;
4     int y; 
5 };
6 struct tagPOINT1 p1;

用途三:用typedef來定義與平台無關的類型。

比如定義一個叫 REAL 的浮點類型,在目標平台一上,讓它表示最高精度的類型為:

1 typedef long double REAL;

在不支持 long double 的平台二上,改為:

1 typedef double REAL;

在連 double 都不支持的平台三上,改為:

1 typedef float REAL;

也就是說,當跨平台時,只要改下 typedef 本身就行,不用對其他源碼做任何修改。

標准庫就廣泛使用了這個技巧,比如size_t。另外,因為typedef是定義了一種類型的新別名,不是簡單的字符串替換,所以它比宏來得穩健。

這個優點在我們寫代碼的過程中可以減少不少代碼量哦!

用途四:為復雜的聲明定義一個新的簡單的別名。

方法是:在原來的聲明里逐步用別名替換一部分復雜聲明,如此循環,把帶變量名的部分留到最后替換,得到的就是原聲明的最簡化版。舉例: 

1 void (*b[10]) (void (*)()); //原聲明
2 //變量名為b,先替換右邊部分括號里的,pFunParam為別名一:
3 typedef void (*pFunParam)();
4 //再替換左邊的變量b,pFunx為別名二:
5 typedef void (*pFunx)(pFunParam);
6 //原聲明的最簡化版:
7 pFunx b[10];

理解復雜聲明可用的“右左法則”:從變量名看起,先往右,再往左,碰到一個圓括號就調轉閱讀的方向;

括號內分析完就跳出括號,還是按先右后左的順序,如此循環,直到整個聲明分析完。舉例:

1 int (*func)(int *p); 
//首先找到變量名func,外面有一對圓括號,而且左邊是一個*號,這說明func是一個指針;
//然后跳出這個圓括號,先看右邊,又遇到圓括號,這說明(*func)是一個函數,所以func是一個指向這類函數的指針,即函數指針,這類函數具有int*類型的形參,返回值類型是int。
1 int (*func[5])(int *);  
//func右邊是一個[]運算符,說明func是具有5個元素的數組;
//func的左邊有一個*,說明func的元素是指針(注意這里的*不是修飾func,而是修飾func[5]的,原因是[]運算符優先級比*高,func先跟[]結合)。
//跳出這個括號,看右邊,又遇到圓括號,說明func數組的元素是函數類型的指針,它指向的函數具有int*類型的形參,返回值類型為int。

這種用法是比較復雜的,出現的頻率也不少,往往在看到這樣的用法卻不能理解,相信以上的解釋能有所幫助。

三、#define和typedef的區別

1) #define是預處理指令,在編譯預處理時進行簡單的替換,不作正確性檢查,不關含義是否正確照樣帶入,只有在編譯已被展開的源程序時才會發現可能的錯誤並報錯。例如:

#define PI 3.1415926

程序中的:area=PI*r*r 會替換為3.1415926*r*r

如果你把#define語句中的數字9 寫成字母g 預處理也照樣帶入。

2)typedef是在編譯時處理的。它在自己的作用域內給一個已經存在的類型一個別名,但是You cannot use the typedef specifier inside a function definition。

3)typedef int * int_ptr; 和 #define int_ptr int * 

作用都是用int_ptr代表 int * ,但是二者不同,正如前面所說 ,#define在預處理時進行簡單的替換,而typedef不是簡單替換 ,而是采用如同定義變量的方法那樣來聲明一種類型。也就是說;

1 //refer to (xzgyb(老達摩))
2 #define int_ptr int *
3 int_ptr a, b; //相當於int * a, b; 只是簡單的宏替換
4 
5 typedef int* int_ptr;
6 int_ptr a, b; //a, b 都為指向int的指針,typedef為int* 引入了一個新的助記符

這也說明了為什么下面觀點成立

1 //QunKangLi(維護成本與程序員的創造力的平方成正比)
2 typedef int * pint ;
3 #define PINT int *

那么:

1 const pint p ;//p不可更改,但p指向的內容可更改
2 const PINT p ;//p可更改,但是p指向的內容不可更改。

pint是一種指針類型 const pint p 就是把指針給鎖住了 p不可更改

而const PINT p 是const int * p 鎖的是指針p所指的對象。

4)還應經注意到#define 不是語句 不要在行末加分號,否則 會連分號一塊置換。

 

補充:

#elif  

     等同於

            #else

            #if 

轉載自:

https://www.cnblogs.com/Jency/articles/C_Cplusplus_define.html

https://blog.csdn.net/dexingchen/article/details/3411680

https://www.cnblogs.com/csyisong/archive/2009/01/09/1372363.html

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM