第四章 運算子的本質

2021-04-01 18:56:41 字數 926 閱讀 8441

陣列是存在於人們頭腦中的乙個邏輯概念,而編譯器其實並不知道有陣列這個東西,它所知道的,只是運算子,當遇到運算子的時候,編譯器只是簡單地把它轉換為類似*(*(a+i)+j)這樣的等價表示式,之所以是這種表示式,如前幾章所述,是因為c語言的陣列實現本質上是陣列的巢狀。

由於這種等價關係的存在,會產生一些古零精怪的表示式,例如:

10[a]

這個表示式初看上去讓人摸不著頭腦,它是什麼呢?如上所述,編譯器會把它轉換為*(10+a),把a和10調換一下,就是*(a+10)了,這個就是a[10]。

運算子之前還可以是乙個表示式,例如:(10+20)[a]。

嚴格來講,以上兩個表示式是非法的,因為c89對於陣列的引用(注意不是陣列定義)規定:帶下標的陣列引用字尾表示式由乙個字尾表示式後跟乙個括在方括號中的表示式組成。方括號前的字尾表示式的型別必須為「指向t型別的指標」,其中t為某種型別;方括號中表示式的型別必須為整型。這個規定說明,進行陣列引用的時候,運算子的左邊並非必須為陣列名,而可以是乙個表示式,但這個表示式的型別必須為「指向某型別的指標」。顯然10跟(10+20)連位址都不是,因此實際上他們是非法的,編譯器在這裡並沒有嚴格遵守標準的規定。但如果是:

int a[10], *p = a;

(p+1)[2]這樣就是合法的,因為p+1的結果仍然是乙個指標。

要注意的是,雖然字尾表示式是乙個「指向某型別的指標」,但不要被這裡所說的指標一詞搞混了,上面的規定不能反過來使用。還是以上面的例子為例,我們可以p[i]這樣使用p,這是符合上述規定的,但並不能因為指標p能夠以p[i]這種形式使用就認為p是乙個陣列,這就錯誤了,不能反過來應用上述規則。

最後說一下編譯器對&*的優化,對於陣列int a[10],如果對其中乙個元素取位址,例如&a[1],這條表示式等價於&*(a+1),編譯器並不會先計算*再運算&,而是對&*兩個運算子進行優化,把它們同時去掉,因為兩者的作用是相反的,最後得到計算的是a+1表示式。

第四章 運算子的本質

陣列是存在於人們頭腦中的乙個邏輯概念,而編譯器其實並不知道有陣列這個東西,它所知道的,只是運算子,當遇到運算子的時候,編譯器只是簡單地把它轉換為類似 a i j 這樣的等價表示式,之所以是這種表示式,如前幾章所述,是因為c語言的陣列實現本質上是陣列的巢狀。由於這種等價關係的存在,會產生一些古零精怪的...

第四章 運算子的本質

陣列是存在於人們頭腦中的乙個邏輯概念,而編譯器其實並不知道有陣列這個東西,它所知道的,只是運算子,當遇到運算子的時候,編譯器只是簡單地把它轉換為類似 a i j 這樣的等價表示式,之所以是這種表示式,如前幾章所述,是因為c語言的陣列實現本質上是陣列的巢狀。由於這種等價關係的存在,會產生一些古零精怪的...

第四章 運算子的本質

陣列是存在於人們頭腦中的乙個邏輯概念,而編譯器其實並不知道有陣列這個東西,它所知道的,只是運算子,當遇到運算子的時候,編譯器只是簡單地把它轉換為類似 a i j 這樣的等價表示式,之所以是這種表示式,如前幾章所述,是因為c語言的陣列實現本質上是陣列的巢狀。由於這種等價關係的存在,會產生一些古零精怪的...