《再再論指針》後記

 

  在這篇後記中,筆者將對三個問題進行補充:

一、關於數組名取地址的問題。c89、c99允許對數組名取地址,是由於數組符合一個對象的定義,按照一

        個對象的語義,對其取地址是合理的。但矛盾在於,數組名是一個符號地址,是一個右值,對其取地址不

        符合&運算符的語法。c89、c99委員會經過權衡,認爲維護一個對象的合理性比一個運算符更重要、更合

        理,因此允許對數組名取地址。但是,&a的意義,已經不是對一個數組名取地址,而是對一個數組對象取

        地址,因此,&a所代表的地址值纔跟a地址值一樣,同時sizeof(&a)應該等於sizeof(a)。c89、c99對這個

        觀點是這樣闡述的:

        Some implementations have not allowed the & operator to be applied to an array or a function.(The construct was permitted in early versions of C, then later made optional.) The C89 Committee endorsed the construct since it is unambiguous, and since data abstraction is enhanced by allowing the important & operator to apply uniformly to any addressable entity.

二、對於二級const指針間的賦值,筆者曾經在第九章舉了一個例子,以說明二級const指針間的賦值會導

        致一個常量被修改。這裏再補充一條理由。以const int *p1和int *p2爲例類型比較涉及兩個方面。首先,p1

       和p2所指向的對象都是int,這是相容的;p1帶有const而p2沒有,這也是相容的,因爲它符合“指針間賦

       值左值要包含右值所有的限定詞”這條規則。但對於const int ** p1和int **p2來說,情況就不一樣了。雖然

       p1仍然符合“左值包含右值所有限定詞”規則,但p1所指向的對象是一個指向const對象的指針,而p2所指

       向的對象卻是一個指向非const對象的指針,兩者的類型不相容,因此p1=p2非法。這條理由是一種已過時

       的現象,更多地存在於早期的編譯器裏,由於它往往讓用戶難以理解,因此後期的編譯器都傾向於允許這種

       賦值。

三、關於p()與(*p)()之間的爭論,有人提出,由於c89存在一條隱含聲明,會使得p()這種形式存在危險

        性。

        首先,c89、c99推薦使用p()這種形式已經是蓋棺定論的事實,兩個標準是這樣說的:

        Pointers to functions may be used either as (*pf)() or as pf(). The latter construct, not sanctioned in K&R, appears in some present versions of C, is unambiguous, invalidates no old code, and can be an important shorthand. The shorthand is useful for packages that present  only one external name, which designates a structure full of pointers to objects and functions: member functions can be called as graphics.open(file) instead of (*graphics.open)(file).
...........................
        The C89 Committee saw no real harm in allowing these forms; outlawing forms like (*f)(), while still permitting *a for a[], simply seemed more trouble than it was worth.

可見(*p)()這種形式是K&R時代的舊式規定,c89、c99仍然支持它只不過是因爲對舊代碼的支持。

        第二,這些人以爲,未聲明p而使用p()的時候,由於這條隱含聲明的存在,p就是已被聲明瞭,這是對隱

        含聲明的錯誤理解,實際上c89、c99只是把這種情況下的p()當作extern int p();而已,在語法上,p仍

        然是一個未聲明的標識符!它違反了另一條規則:一個標識符應當在聲明之後才能使用。但它不應該象其

        它未聲明標識符那樣產生一條error,否則隱含聲明跟不存在沒有什麼兩樣。它應該產生一條warning,以

        說明p是undefined或者函數原型未聲明。

        如果一定要說會產生什麼問題的話,那就是可能會有某些程序員忽略這個warning,這會產生一些問題。

        但這是設計者的原因,不是標準的原因。出於杜絕這種隱患的原因,c99乾脆廢除了c89的隱含聲明,以使

        編譯器產生一條error。c99關於這一點是這樣說的:

        The rule for implicit declaration of functions has been removed in C99.The effect is to guarantee the production of a diagnostic that will catch an additional category of programming errors.

第四點寫於11月8日

第四。第十章筆者解釋了函數的返回值不能爲數組的原因,文中筆者是這樣寫的:

int func(void) [5];

func是一個返回值爲具有5個int元素的數組的函數。但C語言的函數返回值不能爲數組,這是因爲如果允許函數返回值爲數組,那麼接收這個數組的內容的東西,也必須是一個數組,但C語言的數組名是一個右值,它不能作爲左值來接收另一個數組,因此函數返回值不能爲數組。

以上這個解釋有偏差,不應當用數組名來解釋這個問題,因爲數組名不是數組對象的引用,在C中,沒有對數組對象的引用,因此,函數的返回值不能爲數組。

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