轉)const T 與T const的比較(const T vs.T const的翻譯 Dan Saks)

(轉)const T 與T const的比較(const T vs.T const的翻譯 Dan Saks)

C   2009-11-13 09:46   閱讀36   評論0  
字號:    

    
 

版權所有 允許轉載,請註明原創網址,否則追究其法律責任

原創網址:http://blog.csdn.net/night_elf_1020/archive/2008/12/06/3460715.aspx

CSDN :night_elf_1020  小武

謝謝jiahaojie的修改意見

 

在我的上一個專欄裏,我討論了爲什麼C++在數據存入ROM所使用的規則比C語言所使用的規則稍微複雜原因的其中一個。關於這個話題現在我有更多的內容想說,但是在那之前,我很樂意先回答Phil Baurer先生通過E-mail向我諮詢的一個關於小松(日本一個地方)小型採礦系統的問題:

“我們正在對使用帶有typedef的const的問題饒有興趣。我希望您評論下這種用法。我正在思考是不是我們碰巧遇到了一些我們不知道的C語言規則”

“我們正在Hitachi SH-2 32位 RISC微控制器上使用Hitachi C編譯器。我們認爲下面的代碼:

typedef void *VP;

const VP vectorTable[]

= {..<data>..};     (1)

應該等同於:

const void *vectorTable[]

= {..<data>..};     (2)”

“然而,連接器把vectorTable放在(1)中CONSTANT部分,但是(2)中方在了DATA部分。”

“這是合適的做法嗎或者還是編譯器的一個BUG?”

這是一個恰當的做法,不是BUG。你確實碰巧遇到了一些你顯然不知道的C語言規則。不要沮喪,我的朋友,不僅僅是你這樣,我相信很多其他的C和C++程序員對這些規則都很困惑,這也正是我這期專欄想要解決的問題。

我在早期專欄裏提到過一些這些規則,然而,現在回顧那些文章,我認爲我沒有充分的解釋清楚這個問題的根本所在,現在就讓我再解釋一次。

聲明

這裏是第一個觀點:

在C和C++中每一個聲明符都有兩個基本部分組成:一串由個零個或多個字符組成的類型修飾符,以及由一個或多個聲明符;中間用逗號隔開。

(Every declaration in C and C++ has two principal parts: a sequence of zero or more declaration specifiers, and a sequence of one or more declarators, separated by commas.)

例如:static unsigned long int       *x[N];

declaration specifiers      declarator

一個聲明符就是一個被聲明的名字,可能被很多操作符類似如*, [], (), and (在C++中).&連在一起。正如你已經知道的,這個符號“*”代表指針而“[]”意思是數組。這樣*x[N]這個聲明符就表示X是一個含有N個元素的在聲明符中已經制定了的指針數組。例如:static unsigned long int *x[N];表示聲明變量對象X是一個指向含有N個unsigned long int型數據的指針數組(在後面將解釋關鍵詞static並不在對類型起作用)。

我們怎麼知道*x[N]是一個數組指針還是一個指針數組哪?有以下規則:對聲明符的操作順序取決於的修飾符在一個表達式中表現的優先級。

例如,如果你參照下最近無論是C還是C++的優先級列表,你都將看到[]比*優先級高,這樣在聲明*X[N]中X首先是一個數組,其次它是一個指針。

圓括號在這個聲明符中有兩種作用:首先,函數調用操作,()與[]有相同的優先級;在分組時,()擁有最高的優先級。例如:*f(int)聲明f是一個函數,返回指針類型。相反(*f)(int)是一個指向函數的指針。一個聲明符通常包含不止一個標誌符。這個聲明*x[N]包含兩個標誌符,x和N。僅僅一個標識符是需要被聲明的,其他的必須在前面聲明。也就是說x[N]聲明的標誌符是x。.

一個聲明符沒有必要包含太多的操作。在一個聲明中:int n;沒有做除聲明n意外的任何操作。

聲明指定

一些聲明修飾符可以指定一些聲明符爲int、unsigned等類型,或者一個新類型的標誌符,也可以被聲明爲某個如extern或者static的類型。C++中也可以用inline或者virtual來修飾聲明函數標誌符。這裏有這樣一個觀點:

類型修飾符爲標誌符類型的標誌ID,其他的修飾符提供了非類型信息但是卻直接對標誌ID有用。

例如:static unsigned long int *x[N];

聲明符x是一個含有N個unsigned long int數據的指針數組,關鍵詞static表明C只有靜態分配內存。在你信中提到的例子另我懷疑你可能正在被這樣一個事實迷惑:關鍵詞const和valatile是類型修飾符。例如,const在(2)中,並沒有直接修飾vectorTable,而是修飾的void 。這表明vectorTable作爲一個const void類型的指針數組,似乎你希望它是指向void的一個數組常指針。

這裏還有一個重要的觀點:在聲明修飾符中的順序與聲明的順序不匹配。

例如:const VP vectorTable[]等同於VP const vectorTable[],而const void *vectorTable[]等同於void const *vectorTable[]。

我們大都把存儲器類聲明符比如static放在聲明符第一位(最左邊),但是僅僅是通常情況下,不是語言的需要。聲明符const 和volatile與此不同:不僅僅能出現在聲明修飾符中,也能用作聲明符。例如const在void *const vectorTable[]作爲聲明符,這種情況下你不能確定關鍵詞的順序,例如*const void vectorTable[]就是個錯誤的例子。

一種提倡的代碼風格

正如我前面所解釋的,聲明修飾符的順序取決於編譯器,而與聲明的順序無關,因此const void *vectorTable[] (3)和 void const *vectorTable[] (4)等價。幾乎所有的C和C++程序員更喜歡類似(3)式寫const和volatile在表達式的最左邊,而我更喜歡寫它們在類似(4)的最右邊,並且強烈推薦這種方式。

儘管C和C++大都是從頂向下和從左自右,然而指針聲明符一定意義上說是逆着來。也就是說指針聲明符是從右向左的,並且使const出現在最右邊。例如聲明T const *p;聲明瞭一個指向常T類型的指針,而T *const p;聲明瞭一個指向T類型的常指針。把const寫在其他聲明符的右邊能使const限制符的作用更容易分辨。使用原來在信中的例子:typedef void *VP;

const VP vectorTable[]。

一種解釋是替換VP:

const VP vectorTable[]

const void *vectorTable[]

這似乎使得vectorTable是指向一個常void類型指針數組的意義顯得更明顯。但是這是錯誤的。正確的理解是替換VP爲

const VP vectorTable[]

void *const vectorTable[]

這樣,vectorTable一個指向空類型常指針數組,但是一點也不明顯。

把const寫在聲明符的最右邊能使它更容易解釋:

VP const vectorTable[]

void *const vectorTable[]

現在,我意識到我在建議一種很少人用的風格。僅僅針對每一個用const的在左面的使用者。然而,究竟會有多少C和C++程序員明白他們在使用const的地方到底在做什麼。每個人都不這樣做是對現在流行的風格的支持的一個爭論。只要我還在從事這個行業,我就會義無反顧的支持這種風格。雖然很多C程序員對此沒有任何影響,但是許多c++程序員卻不幸的養成了這樣一個書寫習慣。

const int* p;

而不是

const int *p;

這就是說,他們把空格和*作爲聲明修飾符一起使用而不是聲明符。用這種風格寫代碼的話,我真的相信C++程序員這麼做並且互相製造麻煩。的確,空格的位置對編譯器來說沒有任何區別,但是把空格放在*後面一會造成一種錯誤的表象在理解聲明符的時候。意識到在最後聲明修飾符和聲明符的分界點是理解聲明符一個重要關鍵之一。用空格分開只能令人產生迷惑的情形。

我希望我的回答能令你滿意並且澄清了你的疑惑。


本文來自CSDN博客,轉載請標明出處:http://blog.csdn.net/night_elf_1020/archive/2008/12/06/3460715.aspx

發佈了7 篇原創文章 · 獲贊 0 · 訪問量 4萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章