【C++】define 和typedef 的詳細區別

typedef int * int_ptr;
#define INT_PTR int *
const int_ptr p; //p不可更改,但p指向的內容可更改
const INT_PTR p; //p可更改,但是p指向的內容不可更改
int_ptr是一種類型(類型本身就是整型指針),const int_ptr p就是把指針給鎖住了p不可更改,而const INT_PTR p是const int * p鎖的是指針p所指的對象。這些使用常常使我迷惑,所以蒐集整理對他們的理解如下:

#define的用法:

1、簡單的宏定義 #define MAXTIME 1000一個簡單的MAXTIME就定義好了,它代表1000,如果在程序裏面寫:
if(i<MAXTIME){}編譯器在處理這個代碼之前會對MAXTIME進行處理替換爲1000。
這樣的定義看起來類似於普通的常量定義const,但也有着不同,因爲define的定義只是簡單的替換,而不是作爲一個量來使用,這個問題在下面反映的尤爲突出。

2、帶參數的宏
define可以像函數那樣接受一些參數,如下:

#define max(x,y) (x)>(y)?(x):(y);
它將返回兩個數中較大的那個,這個“函數”沒有類型檢查,就好像一個函數模板似的,當然,不難看出它絕對沒有模板那麼安全。
因爲這樣做的話存在隱患,例子如下:

#define Add(a,b) a+b;
一般的單獨使用是沒有問題的,但是如果遇到如:c * Add(a,b) * d的時候就會出現問題,代數式的本意是a+b然後和c,d相乘,但是因爲使用了define(它只是一個簡單的替換),所以式子實際上變成了c*a + b*d 。
再看看這個例子:

#define int_ptr int *;
int_ptr a,b;
本意是a和b都是int型指針,但是實際上變成
int* a,b;
a是int型指針,而b是int型變量。這時應該使用typedef定義:
typedef int* int_ptr;
int_ptr a,b;
這樣a和b就都是int型指針了。

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

#define MACRO(arg1, arg2) do { /
/
stmt1; /
stmt2; /
/
} while(0)
關鍵是要在每一個換行的時候加上一個"/"。

4、在大規模的開發過程中,特別是跨平臺和系統的軟件裏,define最重要的功能是條件編譯。

#ifdef WINDOWS


#endif
#ifdef LINUX


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

5、如何定義宏、取消宏

//定義宏
#define [MacroName] [MacroValue]
//取消宏
#undef [MacroName]
//普通宏
#define PI (3.1415926)
//帶參數的宏
#define max(a,b) ((a)>(b)? (a),(b))
關鍵是十分容易產生錯誤,包括機器和人理解上的差異等等。

6、條件編譯
#ifdef XXX…(#else) …#endif
例如:

#ifdef DV22_AUX_INPUT
#define AUX_MODE 3
#else
#define AUY_MODE 3
#endif


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不是簡單替換,而是採用如同定義變量的方法那樣來聲明一種類型。也就是說;

//refer to (xzgyb(老達摩))
#define int_ptr int *
int_ptr a, b; //相當於int * a, b; 只是簡單的宏替換

typedef int* int_ptr;
int_ptr a, b; //a, b 都爲指向int的指針,typedef爲int* 引入了一個新的助記符


這也說明了爲什麼下面觀點成立
//QunKangLi(維護成本與程序員的創造力的平方成正比)
typedef int * pint ;
#define PINT int *

那麼:
const pint p ;//p不可更改,但p指向的內容可更改
const PINT p ;//p可更改,但是p指向的內容不可更改。

pint是一種指針類型 const pint p 就是把指針給鎖住了 p不可更改
而const PINT p 是const int * p 鎖的是指針p所指的對象。

3)也許您已經注意到#define 不是語句不要在行末加分號,否則會連分號一塊置換。
4)也許您已經注意到#define不是語句,不要在行末加分號,否則會連分號一塊置換;但是typedef結束必須加分號,因爲它是語句。


typedef只是爲了增加可讀性而爲標識符另起的新名
#define原本在C中是爲了定義常量,const、enum、inline的出現使它也漸漸成爲了起別名的工具

爲了儘可能地兼容,一般都遵循:
#define定義“可讀”的常量以及一些宏語句的任務(包括無參量與帶參量)
typedef則常用來定義關鍵字、冗長的類型的別名。


陷阱一:
記住,typedef是定義了一種類型的新別名,不同於宏,它不是簡單的字符串替換。比如:
先定義:
typedef   char*   PSTR;
然後:
int   mystrcmp(const   PSTR,   const   PSTR);

const   PSTR實際上相當於const   char*嗎?不是的,它實際上相當於char*   const。
原因在於const給予了整個指針本身以常量性,也就是形成了常量指針char*   const。
簡單來說,記住當const和typedef一起出現時,typedef不會是簡單的字符串替換就行。

陷阱二:
typedef在語法上是一個存儲類的關鍵字(如auto、extern、mutable、static、register等一樣),雖然它並不真正影響對象的存儲特性,如:
typedef   static   int   INT2;   //不可行
編譯將失敗,會提示“指定了一個以上的存儲類”。

=================typedef使用大全(結構體)

typedef struct _TS1{
    int x, y;
} TS1, *PTS1, ***PPPTS1; // TS1是結構體的名稱,PTS1是結構體指針的名稱
// 也就是將結構體struct _TS1 命名爲TS1,
// 將struct _TS1 * 命名爲 PTS1
// 將struct _TS1 *** 命名爲 PPPTS1

typedef struct { // struct後面的結構體說明也可以去掉
    int x, y;
} TS2, *PTS2;

typedef PTS1 *PPTS1; // 定義PPTS1是指向PTS1的指針

typedef struct _TTS1{
    typedef struct ITTS1 {
        int x, y;
    } iner;
    iner i;
    int x, y;
} TTS1;

//結構體內部的結構體也一樣可以定義
typedef TTS1::ITTS1 ITS1;


void test_struct()
{
    // 基本結構體重定義的使用
    TS1 ts1 = {100, 200};
    PTS1 pts1 = &ts1; // 完全等價於TS1* pts1 = &ts1;
    PPTS1 ppts1 = &pts1; // 完全等價於TS1** ppts1 = &pts1;
    PPPTS1 pppts1 = &ppts1; // 完全等價於 TS1*** pppts1 = &ppts1;

    TS2 ts2 = {99, 88};
    PTS2 pts2 = &ts2;   // 完全等價於 TS2* pts2 = &ts2;

    TTS1 itts1 = {{110, 220}, 10, 20};
    Its1* rits1 = &itts1.i;
    ITS1* &its1 = rits1; // 等價於 TTS1::ITTS1 *its1 = &(itts1.i);

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章