程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> 關於C語言 >> 預處理命令與用typedef命名已有類型,預處理typedef

預處理命令與用typedef命名已有類型,預處理typedef

編輯:關於C語言

預處理命令與用typedef命名已有類型,預處理typedef


  預處理命令

主要是改進程序設計環境,以提高編程效率,不屬於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),可以起到使類型易於記憶的功能。 

如:

  1. typedef int (*PF) (const char *, const char *); 

定義一個指向函數的指針的數據類型PF,其中函數返回值為int,參數為const char *。

typedef 有另外一個重要的用途,那就是定義機器無關的類型,例如,你可以定義一個叫 REAL 的浮點類型,在目標機器上它可以i獲得最高的精度:

  1. typedef long double REAL; 

在不支持 long double 的機器上,該 typedef 看起來會是下面這樣:

  1. typedef double REAL; 

並且,在連 double 都不支持的機器上,該 typedef 看起來會是這樣:

  1. typedef float REAL; 

#define不只是可以為類型取別名,還可以定義常量、變量、編譯開關等。

3. 作用域不同

#define沒有作用域的限制,只要是之前預定義過的宏,在以後的程序中都可以使用。而typedef有自己的作用域。

  1. void fun()   
    {   
    #define A int   
    }  
    void gun()   
    {   
    //在這裡也可以使用A,因為宏替換沒有作用域,   
    //但如果上面用的是typedef,那這裡就不能用A ,不過一般不在函數內使用typedef  
    } 

4. 對指針的操作

二者修飾指針類型時,作用不同。

  1. 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末尾的標號也是不一樣的,希望大家不要忽略這一點。通過本文的分析,相信你已經了解了這兩者之間的區別。掌握了區別之後,運用起來會更加的靈活。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved