青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

專注于服務(wù)器編程、網(wǎng)絡(luò)編程

~~保持一顆平常心~~持之以恒~~
posts - 18, comments - 7, trackbacks - 0, articles - 0
  C++博客 :: 首頁 :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理
       
        右左法則是一個既著名又常用的方法。不過,右左法則其實并不是C標(biāo)準(zhǔn)里面的內(nèi)容,它是從C標(biāo)準(zhǔn)的聲明規(guī)定中歸納出來的方法。C標(biāo)準(zhǔn)的聲明規(guī)則,是用來解決如何創(chuàng)建聲明的,而右左法則是用來解決如何辯識一個聲明的,兩者可以說是相反的。右左法則的英文原文是這樣說的:

The right-left rule: Start reading the declaration from the innermost parentheses, go right, and then go left. When you encounter parentheses, the direction should be reversed. Once everything in the parentheses has been parsed, jump out of it. Continue till the whole declaration has been parsed.


這段英文的翻譯如下:

右左法則:首先從最里面的圓括號看起,然后往右看,再往左看。每當(dāng)遇到圓括號時,就應(yīng)該掉轉(zhuǎn)閱讀方向。一旦解析完圓括號里面所有的東西,就跳出圓括號。重復(fù)這個過程直到整個聲明解析完畢。

        筆者要對這個法則進(jìn)行一個小小的修正,應(yīng)該是從未定義的標(biāo)識符開始閱讀,而不是從括號讀起,之所以是未定義的標(biāo)識符,是因為一個聲明里面可能有多個標(biāo)識符,但未定義的標(biāo)識符只會有一個。

        現(xiàn)在通過一些例子來討論右左法則的應(yīng)用,先從最簡單的開始,逐步加深:

int (*func)(int *p);

首先找到那個未定義的標(biāo)識符,就是func,它的外面有一對圓括號,而且左邊是一個*號,這說明func是一個指針,然后跳出這個圓括號,先看右邊,也是一個圓括號,這說明(*func)是一個函數(shù),而func是一個指向這類函數(shù)的指針,就是一個函數(shù)指針,這類函數(shù)具有int*類型的形參,返回值類型是int。

int (*func)(int *p, int (*f)(int*));

func被一對括號包含,且左邊有一個*號,說明func是一個指針,跳出括號,右邊也有個括號,那么func是一個指向函數(shù)的指針,這類函數(shù)具有int *和int (*)(int*)這樣的形參,返回值為int類型。再來看一看func的形參int (*f)(int*),類似前面的解釋,f也是一個函數(shù)指針,指向的函數(shù)具有int*類型的形參,返回值為int。

int (*func[5])(int *p);

func右邊是一個[]運(yùn)算符,說明func是一個具有5個元素的數(shù)組,func的左邊有一個*,說明func的元素是指針,要注意這里的*不是修飾func的,而是修飾func[5]的,原因是[]運(yùn)算符優(yōu)先級比*高,func先跟[]結(jié)合,因此*修飾的是func[5]。跳出這個括號,看右邊,也是一對圓括號,說明func數(shù)組的元素是函數(shù)類型的指針,它所指向的函數(shù)具有int*類型的形參,返回值類型為int。


int (*(*func)[5])(int *p);

func被一個圓括號包含,左邊又有一個*,那么func是一個指針,跳出括號,右邊是一個[]運(yùn)算符號,說明func是一個指向數(shù)組的指針,現(xiàn)在往左看,左邊有一個*號,說明這個數(shù)組的元素是指針,再跳出括號,右邊又有一個括號,說明這個數(shù)組的元素是指向函數(shù)的指針。總結(jié)一下,就是:func是一個指向數(shù)組的指針,這個數(shù)組的元素是函數(shù)指針,這些指針指向具有int*形參,返回值為int類型的函數(shù)。

int (*(*func)(int *p))[5];

func是一個函數(shù)指針,這類函數(shù)具有int*類型的形參,返回值是指向數(shù)組的指針,所指向的數(shù)組的元素是具有5個int元素的數(shù)組。

要注意有些復(fù)雜指針聲明是非法的,例如:

int func(void) [5];

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

int func[5](void);

func是一個具有5個元素的數(shù)組,這個數(shù)組的元素都是函數(shù)。這也是非法的,因為數(shù)組的元素除了類型必須一樣外,每個元素所占用的內(nèi)存空間也必須相同,顯然函數(shù)是無法達(dá)到這個要求的,即使函數(shù)的類型一樣,但函數(shù)所占用的空間通常是不相同的。

        作為練習(xí),下面列幾個復(fù)雜指針聲明給讀者自己來解析,答案放在第十章里。

int (*(*func)[5][6])[7][8];

int (*(*(*func)(int *))[5])(int *);

int (*(*func[7][8][9])(int*))[5];

        實際當(dāng)中,需要聲明一個復(fù)雜指針時,如果把整個聲明寫成上面所示的形式,對程序可讀性是一大損害。應(yīng)該用typedef來對聲明逐層分解,增強(qiáng)可讀性,例如對于聲明:

int (*(*func)(int *p))[5];

可以這樣分解:

typedef  int (*PARA)[5];
typedef PARA (*func)(int *);

這樣就容易看得多了。

const一詞是英文constant的縮寫,設(shè)立這個關(guān)鍵字的本意,是希望讓它所修飾的對象成為一個常量。記得在國家間的外交中,有一個經(jīng)常用到的術(shù)語:“從事與身份不符的活動”,這個const恰恰也正從事著這樣的活動,呵呵。C語言可以有三種方法定義一個常量:#define、const和枚舉,但只有枚舉才是真正的常量,什么是真正的常量?真正的常量是沒有存儲空間的,是一個右值,這意味著通過任何合法的手段也不會被修改,但被const修飾的對象依然是一個左值,盡管這個對象被const限定,筆者仍然至少可以找到三種合法的手段去修改它,而#define所做的只不過是編譯期替換而已,只有枚舉常量才能真正做到這一點(diǎn)。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ǎn)蹩腳,又常又變的,容易讓人摸不著頭腦,最好還是不要這樣稱呼。這里還得再強(qiáng)調(diào)一次指針常量與地址常量是不同的,不能把數(shù)組名稱為指針常量,也不能把指針常量稱為地址常量,因為指針常量依然是一個左值,而數(shù)組名是一個右值,這里肯定有人會問:“什么?指針常量是一個左值?我沒聽錯吧?”你的確沒有聽錯,C89對于左值是這樣定義的:

對象是一個命名的存儲區(qū)域,左值(lvalue)是引用某個對象的表達(dá)式。

換言之,如果一個表達(dá)式引用的是一個具有具體存儲空間的對象,它就是一個左值!那么既然指針常量是一個左值,為什么卻不能給它賦值呢?是因為它受限于賦值表達(dá)式的一條規(guī)則:賦值表達(dá)式的左值不能含有限定詞!

        為了防止指針指向的常量被修改,C標(biāo)準(zhǔn)對于指針間賦值有一個規(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ī)定,作為左值接受這個一級地址的指針就必須也是一個指向常量的一級指針,于是就不能進(jìn)行下一步賦值20的操作。因此,正由于指向const對象的二級指針p1的出現(xiàn),使得*p1也是一個指向const的指針,于是*p1=&i能夠合法地運(yùn)行,常量i的值被修改也就成了一個預(yù)想中的結(jié)果了。有鑒于此,某些編譯器也會限定非const二級指針之間的賦值,規(guī)定上面的p1=&p2也是非法的。

        第七章介紹聲明符的指針部分有一種形式:

* 類型限定符表opt 指針

這種形式產(chǎn)生了一種比較復(fù)雜的帶const的指針,例如:

const int * const *** const ** const p;

這是一個會讓人頭暈?zāi)垦5谋磉_(dá)式,聲明符部分嵌套了九次,如何辨認(rèn)誰是const,誰不是const呢?一旦明白了其中的原則,其實是非常簡單的。第一和最后一個const大家都已經(jīng)很熟悉的了。對于藏在一堆*號中的const,有一個非常簡單的原則:const與左邊最后一個聲明說明符之間有多少個*號,那么就是多少級指針是const的。例如從右數(shù)起第二個const,它與int之間有4個*號,那么p的四級部分就是const的,下面的賦值表達(dá)式是非法的:

**p = (int *const***)10;
但下面的賦值是允許的:
***p=(int*const**)10;
從左邊數(shù)起第二個const,它與int之間有1個*,那么p的一級部分是const的,也就是*****p = (int*const***const*)10;是非法的。

對于一個函數(shù):

void func(void);

我們通常可以定義一個這樣的函數(shù)指針指向它:

void (*p)(void) = func;

通過p調(diào)用func時,通常有兩種寫法:

p();或者(*p)();

 圍繞這兩種寫法,當(dāng)初C89制定的時候曾經(jīng)有過爭論。(*p)();是一種舊式的規(guī)定,舊式規(guī)定圓括號左邊必須具有“函數(shù)”類型,如果是指向函數(shù)的指針,那么必須加上*聲明符。但C89不再把圓括號的左邊限定為“函數(shù)”類型,而是一個后綴表達(dá)式。那么問題就來了,如果p的值是函數(shù)地址,那么*號就是聲明符,但如果p指向的內(nèi)容是函數(shù)地址,*號就得被看作運(yùn)算符了。同一種形式會有兩種解釋,這是一個矛盾。不僅函數(shù)調(diào)用如此,指向數(shù)組的指針也存在這種矛盾。編譯器為了處理這種情況得增加代碼,效率自然就降低了。爭論的最后結(jié)果是誰也不能把對方完全說服,于是就干脆兩種都支持了。筆者認(rèn)為應(yīng)該拋棄舊式的規(guī)定,p();這種形式簡潔明了,又符合函數(shù)的一般形式,何樂而不為?


        第八章練習(xí)的答案,同時給出用typedef的分解方法:


int (*(*func)[5][6])[7][8];

func是一個指向數(shù)組的指針,這類數(shù)組的元素是一個具有5X6個int元素的二維數(shù)組,而這個二維數(shù)組的元素又是一個二維數(shù)組。

typedef int (*PARA)[7][8];
typedef PARA (*func)[5][6];


int (*(*(*func)(int *))[5])(int *);

func是一個函數(shù)指針,這類函數(shù)的返回值是一個指向數(shù)組的指針,所指向數(shù)組的元素也是函數(shù)指針,指向的函數(shù)具有int*形參,返回值為int。

typedef int (*PARA1)(int*);
typedef PARA1 (*PARA2)[5];
typedef PARA2 (*func)(int*);

int (*(*func[7][8][9])(int*))[5];

func是一個數(shù)組,這個數(shù)組的元素是函數(shù)指針,這類函數(shù)具有int*的形參,返回值是指向數(shù)組的指針,所指向的數(shù)組的元素是具有5個int元素的數(shù)組。

typedef int (*PARA1)[5];
typedef PARA1 (*PARA2)(int*);
typedef PARA2 func[7][8][9];

 原文地址 http://blog.csdn.net/megaboy/archive/2005/09/17/482783.aspx

Feedback

# re: 指針右左法則----復(fù)雜指針解析[未登錄]  回復(fù)  更多評論   

2008-09-17 13:07 by 陳梓瀚(vczh)
其實如果寫得出(其實不難)指針和數(shù)組的聲明的EBNF的話,那么直接看就可以反應(yīng)過來了……

# re: 指針右左法則----復(fù)雜指針解析  回復(fù)  更多評論   

2008-12-01 22:15 by 鹿亮
您對編譯原理相當(dāng)熟悉啊

# re: 指針右左法則----復(fù)雜指針解析  回復(fù)  更多評論   

2009-04-03 12:49 by insulted
非常之不錯!

只有注冊用戶登錄后才能發(fā)表評論。
網(wǎng)站導(dǎo)航: 博客園   IT新聞   BlogJava   博問   Chat2DB   管理


青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            国产精品入口夜色视频大尺度 | 免费中文日韩| 亚洲永久在线观看| 国产精品一二三| 欧美在线视频免费观看| 亚洲欧美综合| 国产原创一区二区| 久久人91精品久久久久久不卡| 亚洲视频播放| 国产午夜精品美女毛片视频| 久久久国产成人精品| 久久人91精品久久久久久不卡| 在线欧美电影| 亚洲精品乱码久久久久| 欧美视频一区二| 久久精品成人欧美大片古装| 久久久精品国产99久久精品芒果| 亚洲电影一级黄| 亚洲精品三级| 国产性猛交xxxx免费看久久| 免费短视频成人日韩| 欧美激情视频一区二区三区免费 | 欧美专区福利在线| 久久这里只有| 亚洲一线二线三线久久久| 香蕉av777xxx色综合一区| **欧美日韩vr在线| 日韩网站在线看片你懂的| 国产精品日韩精品欧美在线| 久久影视三级福利片| 欧美国产在线视频| 欧美一区二区三区久久精品 | 日韩一区二区精品葵司在线| 国产日韩欧美中文| 亚洲国产精品电影| 国产日韩欧美二区| 亚洲激情在线激情| 国产一区二区三区网站| 亚洲日韩视频| 亚洲第一区中文99精品| 亚洲一区二区三区四区五区黄| 亚洲国产成人porn| 亚洲欧美日韩在线| 一区二区欧美在线| 久久在线观看视频| 久久久久在线观看| 国产精品狼人久久影院观看方式| 欧美激情国产高清| 精品99一区二区| 亚洲与欧洲av电影| 亚洲午夜伦理| 欧美日韩免费看| 欧美福利一区二区三区| 韩曰欧美视频免费观看| 亚洲小少妇裸体bbw| 夜夜嗨网站十八久久| 久久久久久国产精品一区| 欧美专区一区二区三区| 欧美日韩免费在线| 亚洲国产视频直播| 亚洲国产视频一区二区| 久久国产综合精品| 久久久久久久久岛国免费| 国产欧美日韩专区发布| 亚洲一区二区在线免费观看| 亚洲免费视频一区二区| 欧美视频二区| 亚洲最新色图| 亚洲综合大片69999| 国产精品久久久| 亚洲一区二区不卡免费| 午夜精品国产更新| 国产欧美日韩一区二区三区在线观看 | 国产亚洲高清视频| 午夜宅男久久久| 久久国产精品电影| 国产一区二区三区四区五区美女| 亚洲欧美一区二区精品久久久| 香蕉久久精品日日躁夜夜躁| 国产精品美女久久| 亚洲综合丁香| 久久天堂av综合合色| 激情自拍一区| 欧美不卡一区| 亚洲精品国精品久久99热一| 中文精品一区二区三区| 欧美午夜精品电影| 欧美一区二区三区啪啪| 久热精品在线视频| 亚洲七七久久综合桃花剧情介绍| 欧美二区在线| 在线亚洲国产精品网站| 欧美有码在线视频| 亚洲高清视频的网址| 欧美精品激情blacked18| 一本色道久久综合亚洲精品按摩| 欧美诱惑福利视频| 在线观看精品| 欧美四级电影网站| 欧美一区二区三区的| 亚洲国产精品v| 午夜天堂精品久久久久| 今天的高清视频免费播放成人| 欧美国产日韩一区二区三区| 亚洲视频福利| 亚洲成人资源网| 亚洲男人的天堂在线aⅴ视频| 国产综合激情| 欧美性片在线观看| 久久久久久综合| 中文国产成人精品| 欧美+日本+国产+在线a∨观看| 亚洲视频在线观看免费| 又紧又大又爽精品一区二区| 欧美日韩一区高清| 久久免费视频这里只有精品| 亚洲一区二区成人| 亚洲国产天堂网精品网站| 欧美一区深夜视频| 一本久久a久久免费精品不卡| 国产一区自拍视频| 国产精品久久久久免费a∨| 麻豆av一区二区三区久久| 亚洲一二三区在线观看| 亚洲人成欧美中文字幕| 美女久久一区| 久久久999精品免费| 亚洲小视频在线| 亚洲精品久久久久久下一站| 国产一区视频观看| 欧美调教vk| 欧美久久99| 免费毛片一区二区三区久久久| 亚洲免费影视| 亚洲视频图片小说| 亚洲精品一区在线观看| 亚洲电影免费在线| 麻豆av福利av久久av| 欧美在线观看视频一区二区| 亚洲午夜av在线| 日韩视频中文字幕| 亚洲精品一区二区在线| 亚洲国产成人精品久久久国产成人一区 | 亚洲欧美精品在线| 中文在线资源观看视频网站免费不卡| 亚洲国产欧美日韩精品| 欧美多人爱爱视频网站| 免费在线观看一区二区| 米奇777超碰欧美日韩亚洲| 久久天天躁狠狠躁夜夜av| 久久久精品一区| 久久久久久成人| 久久久久久久久久久成人| 久久视频在线免费观看| 久久免费国产精品| 米奇777在线欧美播放| 欧美不卡高清| 亚洲电影免费观看高清完整版在线观看| 每日更新成人在线视频| 欧美不卡视频| 亚洲三级影片| 99精品视频免费| 午夜精品一区二区三区在线视| 亚洲欧美激情视频在线观看一区二区三区 | 最近中文字幕mv在线一区二区三区四区| 亚洲第一综合天堂另类专| 亚洲国产另类久久精品| 亚洲最新在线视频| 亚洲在线中文字幕| 欧美一区久久| 欧美大片一区二区| 日韩视频在线观看国产| 亚洲综合色激情五月| 久久免费黄色| 欧美日韩中文另类| 国产一区视频在线看| 亚洲国产免费看| 亚洲在线视频观看| 鲁大师成人一区二区三区 | 亚洲欧美视频一区| 久久亚洲不卡| 亚洲三级影片| 久久av二区| 欧美激情在线| 国产一区二区三区精品欧美日韩一区二区三区 | 农村妇女精品| 中国成人亚色综合网站| 久久久精品一区二区三区| 欧美大片免费久久精品三p | 美女精品视频一区| 国产精品久久久99| 亚洲国产一区视频| 欧美一区二区三区视频免费播放| 欧美成年人网站| 亚洲香蕉视频| 欧美精品在线一区二区| 国产中文一区二区| 亚洲视频日本| 欧美激情小视频| 欧美中文字幕|