const一詞是英文constant的縮寫,設(shè)立這個關(guān)鍵字的本意,是希望讓它所修飾的對象成為一個常量。記得在國家間的外交中,有一個經(jīng)常用到的術(shù)語:“從事與身份不符的活動”,這個const恰恰也正從事著這樣的活動,呵呵。C語言可以有三種方法定義一個常量:#define、const和枚舉,但只有枚舉才是真正的常量,什么是真正的常量?真正的常量是沒有存儲空間的,是一個右值,這意味著通過任何合法的手段也不會被修改,但被const修飾的對象依然是一個左值,盡管這個對象被const限定,筆者仍然至少可以找到三種合法的手段去修改它,而#define所做的只不過是編譯期替換而已,只有枚舉常量才能真正做到這一點。const實在不應(yīng)該被命名為const,這會讓人們產(chǎn)生誤解,它應(yīng)該命名為readonly或類似的字眼,意即不能通過被const修飾的對象修改它所指向的對象或者它所代表的對象。但在C的世界里把const稱為常量早已是普遍的現(xiàn)象,那我們就只好隨大流咯,也稱之為常量吧,只要知道它實際上不是真正的常量就行了。
第七章曾經(jīng)討論過const int *p;與int * const p的區(qū)別,這兩個聲明的中文名稱常常搞得混亂不堪。第一個聲明的const是聲明說明符,它修飾p所指向的對象,但p仍然是可變的,這意味著p是一個指向常量的指針,簡稱常量指針。第二個聲明的const是聲明符的一部分,它修飾的對象是p,這意味著p是一個常量,而且是一個指針類型的常量,簡稱指針常量。指針常量又常常被人稱為“常指針”或“常指針變量”,常指針變量這個名稱有點蹩腳,又常又變的,容易讓人摸不著頭腦,最好還是不要這樣稱呼。這里還得再強調(diào)一次指針常量與地址常量是不同的,不能把數(shù)組名稱為指針常量,也不能把指針常量稱為地址常量,因為指針常量依然是一個左值,而數(shù)組名是一個右值,這里肯定有人會問:“什么?指針常量是一個左值?我沒聽錯吧?”你的確沒有聽錯,C89對于左值是這樣定義的:
對象是一個命名的存儲區(qū)域,左值(lvalue)是引用某個對象的表達式。
換言之,如果一個表達式引用的是一個具有具體存儲空間的對象,它就是一個左值!那么既然指針常量是一個左值,為什么卻不能給它賦值呢?是因為它受限于賦值表達式的一條規(guī)則:賦值表達式的左值不能含有限定詞!
為了防止指針指向的常量被修改,C標準對于指針間賦值有一個規(guī)定,就是左值必須包含右值的所有限定詞。 這就限定了一個指向const對象的指針不能賦值給指向非const對象的指針,但反過來就允許。這個規(guī)定初看上去非常合理,但其效用其實只限于一級指針,二級指針間的賦值即使?jié)M足規(guī)定也不再安全,下面舉個例子:
const int i=10;
const int **p1;
int *p2;
p1 = &p2;
*p1 = &i;
*p2 = 20;
現(xiàn)在你會發(fā)現(xiàn),作為常量的i的值被修改了。i的值被修改的關(guān)鍵原因在*p1=&i;這一句,&i是一個指向常量的一級地址,如果沒有二級指針p1,受限于上述規(guī)定,作為左值接受這個一級地址的指針就必須也是一個指向常量的一級指針,于是就不能進行下一步賦值20的操作。因此,正由于指向const對象的二級指針p1的出現(xiàn),使得*p1也是一個指向const的指針,于是*p1=&i能夠合法地運行,常量i的值被修改也就成了一個預(yù)想中的結(jié)果了。有鑒于此,某些編譯器也會限定非const二級指針之間的賦值,規(guī)定上面的p1=&p2也是非法的。
第七章介紹聲明符的指針部分有一種形式:
* 類型限定符表opt 指針
這種形式產(chǎn)生了一種比較復(fù)雜的帶const的指針,例如:
const int * const *** const ** const p;
這是一個會讓人頭暈?zāi)垦5谋磉_式,聲明符部分嵌套了九次,如何辨認誰是const,誰不是const呢?一旦明白了其中的原則,其實是非常簡單的。第一和最后一個const大家都已經(jīng)很熟悉的了。對于藏在一堆*號中的const,有一個非常簡單的原則:const與左邊最后一個聲明說明符之間有多少個*號,那么就是多少級指針是const的。例如從右數(shù)起第二個const,它與int之間有4個*號,那么p的四級部分就是const的,下面的賦值表達式是非法的:
**p = (int *const***)10;
但下面的賦值是允許的:
***p=(int*const**)10;
從左邊數(shù)起第二個const,它與int之間有1個*,那么p的一級部分是const的,也就是*****p = (int*const***const*)10;是非法的。
本文引用通告地址: http://blog.csdn.net/megaboy/services/trackbacks/482769.aspx
[點擊此處收藏本文]
聯(lián)系客服