預處理命令
主要是改進程序設計環境,以提高編程效率,不屬於c語言本身的組成部分,不能直接對它們進行編譯,必須在對 程序編譯之前,先對程序中的這些特殊命令進行“預處理”。比如頭文件。
有以下三類:宏定義,文件包含,條件編譯。
宏定義(分為帶參數與不帶參數兩種)
宏定義是用宏名代替一個字符串,也是簡單的置換,不作正確性檢查。
宏定義不是C語句,不必在行未加分號;
#define命令出現在程序中函數的外面,宏名的有限范圍為定義命令之後到本源文件結束。
可以用#undef命令終止宏定義的作用域。
對程序中用雙撇號括起來的字符串內的字符,不進行置換。
宏定義與定義變量不同,只作字符替換,不分配空間;
帶參數的宏定義(不只是進行簡單的字符串替換,還要進行參數替換)
帶參數的宏定義與函數時不同的,主要有以下幾點:
函數調用時,先求出實參表達式的值,然後帶入形參。而宏只是進行簡單的字符替換。
函數調用是在程序運行時處理的,為形參分配臨時的內存單元。而宏展開則是編譯前進行的,在展開時不分配內存單元,不進行值的傳遞處理,也沒有“返回值”的概念。
對函數中的實參和形參都要定義類型,二者要求一致。而宏不存在類型問題,宏名無類型。宏定義時,字符串可以是任何類型的數據。
調用函數只可得到一個返回值,而用宏定義可以設法得到幾個結果。
使用宏次數多時,宏展開後源程序變長,而函數調用不會。
宏替換不占運行時間,只占編譯時間。而函數調用則占運行時間(分配內存,保留現場,返回值)
文件包含
所謂“文件包含”處理就是指一個源文件可以將另一個源文件的全部內容包含進來,即將另外的文件包含到本文件之中。(#include...)
頭文件除了可以包含函數原型和宏定義外,也可以包括結構體類型定義和全局變量定義等。
條件編譯
程序中的某一部分需要滿足一定條件時才進行編譯,也就是對這一部分內容指定編譯的條件,這就是條件編譯。
條件編譯有以下幾種形式:
#ifdef 標識符 程序段1 #else 程序段2 #endif
#if 表達式 程序段1 #else 程序段2 #endif
//條件編譯 #include<stdio.h> #define LETTER 1 void main() { char str[20]="C Language",c; int i=0; while((c=str[i]!='\0')) { i++; #if LETTER if(c>='a'&&c<='z') c=c-32; #else if(c>='A'&&c<='Z') c=c+32; #endif printf("%c",c); } printf("\n"); }
用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; //不可行
編譯將失敗,會提示“指定了一個以上的存儲類”。
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。
1. 首先,二者執行時間不同
關鍵字typedef在編譯階段有效,由於是在編譯階段,因此typedef有類型檢查的功能。
Define則是宏定義,發生在預處理階段,也就是編譯之前,它只進行簡單而機械的字符串替換,而不進行任何檢查。
#define用法例子:
#define f(x) x*x main( ) { int a=6,b=2,c; c=f(a) / f(b); printf("%d \n",c); }
程序的輸出結果是: 36,根本原因就在於#define只是簡單的字符串替換,應當加個括號“(X*X)”。
2. 功能不同
Typedef用來定義類型的別名,這些類型不只包含內部類型(int,char等),還包括自定義類型(如struct),可以起到使類型易於記憶的功能。
如:
定義一個指向函數的指針的數據類型PF,其中函數返回值為int,參數為const char *。
typedef 有另外一個重要的用途,那就是定義機器無關的類型,例如,你可以定義一個叫 REAL 的浮點類型,在目標機器上它可以i獲得最高的精度:
在不支持 long double 的機器上,該 typedef 看起來會是下面這樣:
並且,在連 double 都不支持的機器上,該 typedef 看起來會是這樣:
#define不只是可以為類型取別名,還可以定義常量、變量、編譯開關等。
3. 作用域不同
#define沒有作用域的限制,只要是之前預定義過的宏,在以後的程序中都可以使用。而typedef有自己的作用域。
void fun() { #define A int } void gun() { //在這裡也可以使用A,因為宏替換沒有作用域, //但如果上面用的是typedef,那這裡就不能用A ,不過一般不在函數內使用typedef }
4. 對指針的操作
二者修飾指針類型時,作用不同。
Typedef int * pint; #define PINT int * Const pint p;//p不可更改,p指向的內容可以更改,相當於 int * const p; Const PINT p;//p可以更改,p指向的內容不能更改,相當於 const int *p;或 int const *p; pint s1, s2; //s1和s2都是int型指針 PINT s3, s4; //相當於int * s3,s4;只有一個是指針
其實,typedef和define末尾的標號也是不一樣的,希望大家不要忽略這一點。通過本文的分析,相信你已經了解了這兩者之間的區別。掌握了區別之後,運用起來會更加的靈活。