[C++]函式與編譯預處理(二)

丫就是熊個貓貓發表於2016-11-28

函式與編譯預處理

引數個數可變的函式

到目前為止,在定義函式時,都明確規定了函式的引數個數及型別。在呼叫函式時,實參的個數必須與形參相同。在呼叫具有預設引數值的函式時,本質上,實參的個數與形參的個數仍是相同的,由於引數具有預設值,因此,在呼叫時可省略。在某些應用中,在定義函式時,並不能確定函式的引數個數,引數的個數在調時才能確定。在C++中允許定義引數個數可變的函式。

 

首先,必須包含標頭檔案“stdarg.h”,因為要用到裡面的三個庫函式  va_start( )、va_arg( )和va_end( )。

其次,要說明一個va_list型別的變數。va_list與int,float類同,它是C++系統預定義的一個資料型別(非float),只有通過這種型別的變數才能從實際參數列中取出可變有引數。如:va_list   ap;

va_start(ap,b):初始化

va_arg(ap,int):依次取引數

va_end(ap):正確結束

 

va_start():有兩個引數,va_start(ap,b); b即為可變引數前的最後一個確定的引數。

va_arg():有兩個引數,va_arg(ap,int)    int即為可變引數的資料型別名。

int  temp;

temp=va_arg(ap,int);

va_end():完成收尾工作。va_end(ap);

在呼叫引數個數可變的函式時,必定有一個引數指明可變引數的個數或總的實參個數。如第一個引數值為總的實際引數的個數。

 

使用引數數目可變的函式時要注意以下幾點:

1、在定義函式時,固定引數部分必須放在參數列的前面,可變引數在後面,並用省略號“...”表示可變引數。在函式呼叫時,可以沒有可變的引數。

2、必須使用函式va_start()來初始化可變引數,為取第一個可變的引數作好準備工作;使用函式va_arg()依次取各個可變的引數值;最後用函式va_end()做好結束工作,以便能正確地返回。

3、在呼叫引數個數可變的函式時,必定有一個引數指明可變引數的個數或總的實參個數。

函式的過載

所謂函式的過載是指完成不同功能的函式可以具有相同的函式名。

C++的編譯器是根據函式的實參來確定應該呼叫哪一個函式的。

1、定義的過載函式必須具有不同的引數個數,或不同的引數型別。只有這樣編譯系統才有可能根據不同的引數去呼叫不同的過載函式。

2、僅返回值不同時,不能定義為過載函式。即僅函式的型別不同,不能定義為過載函式

 

編譯預處理

高階語言編譯過程

 

C語言提供的編譯預處理的功能有以下三種:

巨集定義    檔案包含     條件編譯

 

巨集定義

不帶引數的巨集定義

用一個指定的識別符號(即名字)來代表一個字串,以後凡在程式中碰到這個識別符號的地方都用字串來代替。

這個識別符號稱為巨集名,編譯前的替代過程稱為“巨集展開”。

# define    識別符號     字串

#define  PRICE   30  

void main(void)

{    int  num, total;  /*定義變數*/

      num=10;        /*變數賦值*/

     total=num*PRICE;

     cout<<"total=“<<total<<endl;

}

編譯程式將巨集定義的內容認為是字串,沒有任何實際的物理意義。

注意:

1、巨集展開只是一個簡單的“物理”替換,不做語法檢查,不是一個語句,其後不加分號“;”

2、#define命令出現在函式的外面,其有效範圍為定義處至本原始檔結束。可以用# undef命令終止巨集定義的作用域。

#define G  9.8

void main(void )

{.....}

# undef   G

int max(int a,int b)

{...... }

3、對程式中用雙引號括起來的字串內容,即使與巨集名相同,也不進行置換。

4、在進行巨集定義中,可以用已定義的巨集名,進行層層置換。

 

帶引數的巨集定義

 

按#define命令列中指定的字串從左至右進行置換巨集名,字串中的形參以相應的實參代替,字串中的非形參字元保持不變。

 

定義巨集時在巨集名與帶引數的括弧間不能有空格。

#define  S_ (r)   P*r*r

帶引數的巨集與函式呼叫的區別

相同:有實參、形參,代入呼叫。

不同之處

1、函式呼叫先求表示式的值,然後代入形參,而巨集只是機械替換。

2、函式呼叫時形參、實參進行型別定義,而巨集不需要,只是作為字串替代。

3、函式呼叫是在執行程式時進行的,其目的碼短,但程式執行時間長。而巨集呼叫是在編譯之前完成的,執行時已將程式碼替換程式序中,目的碼長,執行時間稍快。

一般用巨集表示實時的、短小的表示式。

 

檔案包含

一個原始檔可以將另外一個原始檔的全部內容包含進來,即將另外的檔案包含到本檔案之中。

#  include   “檔名”

 

注意:

1、檔名是C的原始檔名,是文字檔案,字尾名可以任選。*.cpp *.h

2、一個#include語句只能指定一個被包含檔案。

3、檔名用雙引號或尖括號括起來。

4、包含後所有原始檔編譯為一個可執行檔案。

 

條件編譯

C語言允許有選擇地對程式的某一部分進行編譯。也就是對一部分源程式指定編譯條件。

 

條件編譯有以下幾種形式:

1、  # ifdef      識別符號

         程式段1

     # else

         程式段2

      # end if

當識別符號已被定義過(用#define定義),則對程式段1進行編譯,否則編譯程式段2.

2、  # ifndef      識別符號

            程式段1

     # else

            程式段2

     # endif

與形式1相反,當識別符號沒有被定義過(用#define定義),則對程式段1進行編譯,否則編譯程式段2。

3、 # if     表示式

          程式段1

    # else

          程式段2

# endif  

當表示式為真(非零),編譯程式段1,表示式為零,編譯程式段2。

 

程式的多檔案組織

而在設計一個功能複雜的大程式時,為了便於程式的設計和除錯,通常將程式分成若干個模組,把實現一個模組的程式或資料放在一個檔案中。當一個完整的程式被存放在多於一個檔案中時,稱為程式的多檔案組織。

 

內部函式和外部函式

內部函式:函式只限於在本檔案中呼叫,其它檔案不能呼叫,用static 定義該函式。

static  float  fac( int  n)

{   ......      }

外部函式:函式的預設形式,可以被其它檔案呼叫,用extern 定義該函式。呼叫時,在檔案中用extern 說明。

void main(void)

{  extern  enter_string( );

    char   str[80];

    enter_string(str);

    ..........

}

 

 

相關文章