typedef和#define的用法和差別。本站提示廣大學習愛好者:(typedef和#define的用法和差別)文章只能為提供參考,不一定能成為您想要的結果。以下是typedef和#define的用法和差別正文
1、typedef的用法
在C/C++說話中,typedef經常使用來界說一個標識符及症結字的別號,它是說話編譯進程的一部門,但它其實不現實分派內存空間,實例像:
typedef int INT;
typedef int ARRAY[10];
typedef (int*) pINT;
typedef可以加強法式的可讀性,和標識符的靈巧性,但它也有“非直不雅性”等缺陷。
2、#define的用法
#define為一宏界說語句,平日用它來界說常量(包含無參量與帶參量),和用來完成那些“外面似和氣、面前一長串”的宏,它自己其實不在編譯進程中停止,而是在這之前(預處置進程)就曾經完成了,但也是以難以發明潛伏的毛病及其它代碼保護成績,它的實例像:
#define INT int
#define TRUE 1
#define Add(a,b) ((a)+(b));
#define Loop_10 for (int i=0; i<10; i++)
在Scott Meyer的Effective C++一書的條目1中有關於#define語句弊病的剖析,和好的替換辦法,年夜家可參看。
3、typedef與#define的差別
從以上的概念便也能根本清晰,typedef只是為了增長可讀性而為標識符另起的新稱號(僅僅只是個體名),而#define本來在C中是為了界說常量,到了C++,const、enum、inline的湧現使它也逐漸成了起別號的對象。有時很輕易弄不清晰與typedef二者究竟該用哪一個好,如#define INT int如許的語句,用typedef一樣可以完成,用哪一個好呢?我主意用typedef,由於在晚期的很多C編譯器中這條語句長短法的,只是當今的編譯器又做了擴大。為了盡量地兼容,普通都遵守#define界說“可讀”的常量和一些宏語句的義務,而typedef則經常使用來界說症結字、冗雜的類型的別號。
宏界說只是簡略的字符串代換(原地擴大),而typedef則不是原地擴大,它的新名字具有必定的封裝性,乃至於新定名的標識符具有更容易界說變量的功效。請看下面第一年夜點代碼的第三行:
typedef (int*) pINT;
和上面這行:
#define pINT2 int*
後果雷同?實則分歧!理論中見差異:pINT a,b;的後果同int *a; int *b;表現界說了兩個整型指針變量。而pINT2 a,b;的後果同int *a, b;
表現界說了一個整型指針變量a和整型變量b。
typedef的四個用處和兩個圈套
用處一:
界說一品種型的別號,而不只是簡略的宏調換。可以用作同時聲明指針型的多個對象。好比:
char* pa, pb; // 這多半不相符我們的意圖,它只聲清楚明了一個指向字符變量的指針,
// 和一個字符變量;
以下則可行:
typedef char* PCHAR; // 普通用年夜寫
PCHAR pa, pb; // 可行,同時聲清楚明了兩個指向字符變量的指針
固然:
char *pa, *pb;
也可行,但絕對來講沒有效typedef的情勢直不雅,特別在須要年夜量指針的處所,typedef的方法更省事。
用處二:
用在舊的C代碼中(詳細多舊沒有查),贊助struct。之前的代碼中,聲明struct新對象時,必需要帶上struct,即情勢為: struct 構造名 對象名,如:
struct tagPOINT1
{
int x;
int y;
};
struct tagPOINT1 p1;
而在C++中,則可以直接寫:構造名 對象名,即:
tagPOINT1 p1;
估量或人認為常常多寫一個struct太費事了,因而就創造了:
typedef struct tagPOINT
{
int x;
int y;
}POINT;
POINT p1; // 如許就比本來的方法少寫了一個struct,比擬省事,特別在年夜量應用的時刻
也許,在C++中,typedef的這類用處二不是很年夜,然則懂得了它,對控制之前的舊代碼照樣有贊助的,究竟我們在項目中有能夠會碰到較早些年月遺留上去的代碼。
用處三:
用typedef來界說與平台有關的類型。
好比界說一個叫 REAL 的浮點類型,在目的平台一上,讓它表現最高精度的類型為:
typedef long double REAL;
在不支撐 long double 的平台二上,改成:
typedef double REAL;
在連 double 都不支撐的平台三上,改成:
typedef float REAL;
也就是說,當跨平台時,只需改下 typedef 自己就行,不消對其他源碼做任何修正。
尺度庫就普遍應用了這個技能,好比size_t。
別的,由於typedef是界說了一品種型的新別號,不是簡略的字符串調換,所以它比宏來得穩健(固然用宏有時也能夠完成以上的用處)。
用處四:
為龐雜的聲明界說一個新的簡略的別號。辦法是:在本來的聲明裡慢慢用別號調換一部門龐雜聲明,如斯輪回,把帶變量名的部門留到最初調換,獲得的就是原聲明的最簡化版。舉例:
1. 原聲明:int *(*a[5])(int, char*);
變量名為a,直接用一個新別號pFun調換a便可以了:
typedef int *(*pFun)(int, char*);
原聲明的最簡化版:
pFun a[5];
2. 原聲明:void (*b[10]) (void (*)());
變量名為b,先調換左邊部門括號裡的,pFunParam為別號一:
typedef void (*pFunParam)();
再調換右邊的變量b,pFunx為別號二:
typedef void (*pFunx)(pFunParam);
原聲明的最簡化版:
pFunx b[10];
3. 原聲明:doube(*)() (*e)[9];
變量名為e,先調換右邊部門,pFuny為別號一:
typedef double(*pFuny)();
再調換左邊的變量e,pFunParamy為別號二
typedef pFuny (*pFunParamy)[9];
原聲明的最簡化版:
pFunParamy e;
懂得龐雜聲明可用的“右左軌則”:從變量名看起,先往右,再往左,碰著一個圓括號就調轉浏覽的偏向;括號內剖析完就跳出括號,照樣按先右後左的次序,如斯輪回,直到全部聲明剖析完。舉例:
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是界說了一品種型的新別號,分歧於宏,它不是簡略的字符串調換。好比:
先界說:
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; //弗成行
編譯將掉敗,會提醒“指定了一個以上的存儲類”。