當前位置:編程學習大全網 - 源碼下載 - C語言中為什麽不用#define定義常量?

C語言中為什麽不用#define定義常量?

參考有效C++中的第1章:建議使用const。

子句1:嘗試使用const和inline,而不是#define。

這個子句最好叫做:“嘗試使用沒有預處理的編譯器”,因為#define經常被認為好像不是語言本身的壹部分。這是問題之壹。請看下面的陳述:

#定義縱橫比1.653

編譯器永遠看不到符號名ASPECT_RATIO,因為它會在源代碼進入編譯器之前被預處理器移除,所以ASPECT_RATIO不會被添加到符號列表中。如果這個常量涉及的代碼在編譯時報錯,那就莫名其妙了,因為錯誤信息指的是1.653,而不是ASPECT_RATIO。如果妳自己的頭文件中沒有定義ASPECT_RATIO,妳會想1.653是哪裏來的,甚至會花時間去追查。這個問題也會出現在符號調試器中,因為同樣的,妳寫的符號名也不會出現在符號列表中。

這個問題的解決方案很簡單:定義壹個常量而不預處理宏:

const double ASPECT _ RATIO = 1.653;

這個方法很有效。但是有兩種特殊情況需要註意。

首先,指針常量的定義會有壹點不同。因為常量通常是在頭文件中定義的(很多源文件都會包含它們),所以除了指針所指向的類型之外,指針通常也被定義為const是很重要的。例如,要在頭文件中基於char*定義壹個字符串常量,您必須編寫const兩次:

const char * const author name = " Scott Meyers ";

有關const的含義和用法,尤其是與指針相關的問題,請參見條款21。

另外,定義壹個類的常量壹般比較方便,差別不大。要將壹個常量限制在壹個類中,首先要使它成為該類的成員;為了確保常數最多只有壹個副本,它也被定義為靜態成員:

職業玩家{

私人:

靜態常數int NUM _ TURNS = 5;//常量聲明

int scores[NUM _ TURNS];//常量的使用

...

};

還有壹點,可以看到,上面的語句是NUM_TURNS的聲明,不是定義,所以還必須在類實現代碼文件中定義類的靜態成員:

const int GamePlayer::NUM _ TURNS;//強制定義;

//進入impl.file類

妳不必為這種小事過分擔心。如果妳忘記了定義,鏈接器會提醒妳。

舊的編譯器不會接受這種語法,因為它認為類的靜態成員在聲明時定義初始值是非法的;而且,只支持整數類型(如int、bool、char等。)可以在類內初始化,它們只能是常量。

在無法使用上述語法的情況下,您可以在定義時指定初始值:

class EngineeringConstants { //這放在類中

私有://頭文件

靜態常數雙模糊因子;

...

};

//這放在類實現文件中

const double engineering constants::FUDGE _ FACTOR = 1.35;

大多數情況下,妳只需要做這麽多。唯壹的例外是當妳的類在編譯時需要使用這個類的常量,比如上面的GamePlayer::scores數組的聲明(編譯時編譯器必須知道數組的大小)。因此,為了彌補編譯器(不正確地)禁止在類中初始化整數類常量的缺點,可以采用壹種叫做“借用枚舉”的方法來解決這個問題。這個技術很好的利用了需要int類型時可以使用枚舉類型的原理,所以GamePlayer也可以這樣定義:

職業玩家{

私人:

enum { NUM _ TURNS = 5 }//" enum hack "-使

// NUM_TURNS壹個符號名

//對於5

int scores[NUM _ TURNS];//好吧

};

除非妳用的是老編譯器(也就是1995之前寫的),否則沒必要借用enum。當然,知道有這樣的方法是值得的,因為這種可以追溯到很久以前的代碼並不常見。

回到預處理的話題。#define指令的另壹個常見用途是用它來實現看起來像函數的宏,而不會導致函數調用。壹個典型的例子是計算兩個對象的最大值:

#定義max(a,b) ((a)>(b)?(a) : (b))

這句話有很多缺陷,光是想想就讓人頭疼,甚至比高峰期在高速公路上開車還要痛苦。

每當妳像這樣寫壹個宏的時候,在編寫宏體的時候,壹定要記得給每個參數加上括號;否則如果有人用表達式調用妳的宏,會造成很大的麻煩。但是即使妳這樣做了,還是會發生如下奇怪的事情:

int a = 5,b = 0;

max(++a,b);// a的值增加了兩倍。

max(++a,b+ 10);// a的值只增加了1倍。

在這種情況下,max內部發生什麽取決於它比較什麽值!

幸運的是,妳再也不用忍受這些愚蠢的句子了。您可以使用普通函數來實現宏效率,以及可預測的行為和類型安全。這是內嵌函數(見第33條):

inline int max(int a,int b){ return a & gt;b?甲:乙;}

但是,這和上面的宏不壹樣,因為這個版本的max只能處理int類型。但是模板可以輕松解決這個問題:

模板& ltT類& gt

在線const T & amp最大值(常數T & amp壹、const T & ampb)

{ return a & gtb?甲:乙;}

這個模板產生壹組函數,每個函數比較兩個可以轉換成相同類型的對象,然後返回壹個對較大(常量)對象的引用。因為不知道t的類型,所以在返回時傳遞壹個引用可以提高效率(見第22條)。

順便說壹句,在妳計劃使用模板編寫像max這樣有用的通用函數之前,先檢查壹下標準庫(見第49條)看看它們是否已經存在。比如上面提到的max,妳會驚喜地發現,妳可以為後人乘涼了:max是C++標準庫的壹部分。

有了const和inline,妳需要的預處理就少了,但是完全離不開它。拋棄#include還有很長的路要走,#ifdef/#ifndef在控制編譯方面也有很重要的作用。預處理還不能退休,但是妳壹定要打算經常給它放個長假。

  • 上一篇:健身行業開發微信小程序的好處是什麽
  • 下一篇:誰能教我做尼奧寵物主頁和用戶查找,以及HTML代碼?
  • copyright 2024編程學習大全網