<dfn id="is4kg"></dfn>
  • <ul id="is4kg"></ul>
  • <abbr id="is4kg"></abbr>
  • <ul id="is4kg"></ul>
    <bdo id="is4kg"></bdo>
    以文本方式查看主題

    -  曙海教育集團(tuán)論壇  (http://www.hufushizhe.com/bbs/index.asp)
    --  C++語言開發(fā)  (http://www.hufushizhe.com/bbs/list.asp?boardid=63)
    ----  給粗心的C語言初學(xué)者(1)  (http://www.hufushizhe.com/bbs/dispbbs.asp?boardid=63&id=2430)

    --  作者:wangxinxin
    --  發(fā)布時(shí)間:2010-12-10 14:48:11
    --  給粗心的C語言初學(xué)者(1)
    0 簡介

    C語言及其典型實(shí)現(xiàn)被設(shè)計(jì)為能被專家們?nèi)菀椎厥褂谩_@門語言簡潔并附有表達(dá)力。但有一些限制可以保護(hù)那些浮躁的人。一個(gè)浮躁的人可以從這些條款中獲得一些幫助。


    在本文中,我們將會(huì)看一看這些未可知的益處。這是由于它的未可知,我們無法為其進(jìn)行完全的分類。不過,我們?nèi)匀煌ㄟ^研究為了一個(gè)C程序的運(yùn)行所需要做的事來做到這些。我們假設(shè)讀者對(duì)C語言至少有個(gè)粗淺的了解。


    第一部分研究了當(dāng)程序被劃分為記號(hào)時(shí)會(huì)發(fā)生的問題。第二部分繼續(xù)研究了當(dāng)程序的記號(hào)被編譯器組合為聲明、表達(dá)式和語句時(shí)會(huì)出現(xiàn)的問題。第三部分研究了由多個(gè)部分組成、分別編譯并綁定到一起的C程序。第四部分處理了概念上的誤解:當(dāng)一個(gè)程序具體執(zhí)行時(shí)會(huì)發(fā)生的事情。第五部分研究了我們的程序和它們所使用的常用庫之間的關(guān)系。在第六部分中,我們注意到了我們所寫的程序也不并不是我們所運(yùn)行的程序;預(yù)處理器將首先運(yùn)行。最后,第七部分討論了可移植性問題:一個(gè)能在一個(gè)實(shí)現(xiàn)中運(yùn)行的程序無法在另一個(gè)實(shí)現(xiàn)中運(yùn)行的原因。


    1 詞法缺陷

    編譯器的第一個(gè)部分常被稱為詞法分析器(lexical analyzer)。詞法分析器檢查組成程序的字符序列,并將它們劃分為記號(hào)(token)一個(gè)記號(hào)是一個(gè)有一個(gè)或多個(gè)字符的序列,它在語言被編譯時(shí)具有一個(gè)(相關(guān)地)統(tǒng)一的意義。在C中, 例如,記號(hào)->的意義和組成它的每個(gè)獨(dú)立的字符具有明顯的區(qū)別,而且其意義獨(dú)立于->出現(xiàn)的上下文環(huán)境。


    另外一個(gè)例子,考慮下面的語句:


    if(x > big) big = x;


    該語句中的每一個(gè)分離的字符都被劃分為一個(gè)記號(hào),除了關(guān)鍵字if和標(biāo)識(shí)符big的兩個(gè)實(shí)例。


    事實(shí)上,C程序被兩次劃分為記號(hào)。首先是預(yù)處理器讀取程序。它必須對(duì)程序進(jìn)行記號(hào)劃分以發(fā)現(xiàn)標(biāo)識(shí)宏的標(biāo)識(shí)符。它必須通過對(duì)每個(gè)宏進(jìn)行求值來替換宏調(diào)用。最后,經(jīng)過宏替換的程序又被匯集成字符流送給編譯器。編譯器再第二次將這個(gè)流劃分為記號(hào)。


    在這一節(jié)中,我們將探索對(duì)記號(hào)的意義的普遍的誤解以及記號(hào)和組成它們的字符之間的關(guān)系。稍后我們將談到預(yù)處理器。


    1.1 = 不是 ==

    從Algol派生出來的語言,如Pascal和Ada,用:=表示賦值而用=表示比較。而C語言則是用=表示賦值而用==表示比較。這是因?yàn)橘x值的頻率要高于比較,因此為其分配更短的符號(hào)。


    此外,C還將賦值視為一個(gè)運(yùn)算符,因此可以很容易地寫出多重賦值(如a = b = c),并且可以將賦值嵌入到一個(gè)大的表達(dá)式中。


    這種便捷導(dǎo)致了一個(gè)潛在的問題:可能將需要比較的地方寫成賦值。因此,下面的語句好像看起來是要檢查x是否等于y:


    if(x = y)
    foo();


    而實(shí)際上是將x設(shè)置為y的值并檢查結(jié)果是否非零。在考慮下面的一個(gè)希望跳過空格、制表符和換行符的循環(huán):


    while(c == \' \' || c = \'\\t\' || c == \'\\n\')
    c = getc(f);


    在與\'\\t\'進(jìn)行比較的地方程序員錯(cuò)誤地使用=代替了==。這個(gè)“比較”實(shí)際上是將\'\\t\'賦給c,然后判斷c的(新的)值是否為零。因?yàn)閈'\\t\'不為零,這個(gè)“比較”將一直為真,因此這個(gè)循環(huán)會(huì)吃盡整個(gè)文件。這之后會(huì)發(fā)生什么取決于特定的實(shí)現(xiàn)是否允許一個(gè)程序讀取超過文件尾部的部分。如果允許,這個(gè)循環(huán)會(huì)一直運(yùn)行。


    一些C編譯器會(huì)對(duì)形如e1 = e2的條件給出一個(gè)警告以提醒用戶。當(dāng)你趨勢需要先對(duì)一個(gè)變量進(jìn)行賦值之后再檢查變量是否非零時(shí),為了在這種編譯器中避免警告信息,應(yīng)考慮顯式給出比較符。換句話說,將:


    if(x = y)
    foo();


    改寫為:


    if((x = y) != 0)
    foo();


    這樣可以清晰地表示你的意圖。


    1.2 & 和 | 不是 && 和 ||

    容易將==錯(cuò)寫為=是因?yàn)楹芏嗥渌Z言使用=表示比較運(yùn)算。 其他容易寫錯(cuò)的運(yùn)算符還有&和&&,或|和||,這主要是因?yàn)镃語言中的&和|運(yùn)算符于其他語言中具有類似功能的運(yùn)算符大為不同。我們將在第4節(jié)中貼近地觀察這些運(yùn)算符。


    1.3 多字符記號(hào)

    一些C記號(hào),如/、*和=只有一個(gè)字符。而其他一些C記號(hào),如/*和==,以及標(biāo)識(shí)符,具有多個(gè)字符。當(dāng)C編譯器遇到緊連在一起的/和*時(shí),它必須能夠決定是將這兩個(gè)字符識(shí)別為兩個(gè)分離的記號(hào)還是一個(gè)單獨(dú)的記號(hào)。C語言參考手冊說明了如何決定:“如果輸入流到一個(gè)給定的字符串為止已經(jīng)被識(shí)別為記號(hào),則應(yīng)該包含下一個(gè)字符以組成能夠構(gòu)成記號(hào)的最長的字符串”。因此,如果/是一個(gè)記號(hào)的第一個(gè)字符,并且/后面緊隨了一個(gè)*,則這兩個(gè)字符構(gòu)成了注釋的開始,不管其他上下文環(huán)境。


    下面的語句看起來像是將y的值設(shè)置為x的值除以p所指向的值:


    y = x/*p /* p 指向除數(shù) */;


    實(shí)際上,/*開始了一個(gè)注釋,因此編譯器簡單地吞噬程序文本,直到*/的出現(xiàn)。換句話說,這條語句僅僅把y的值設(shè)置為x的值,而根本沒有看到p。將這條語句重寫為:


    y = x / *p /* p 指向除數(shù) */;


    或者干脆是


    y = x / (*p) /* p指向除數(shù) */;


    它就可以做注釋所暗示的除法了。


    這種模棱兩可的寫法在其他環(huán)境中就會(huì)引起麻煩。例如,老版本的C使用=+表示現(xiàn)在版本中的+=。這樣的編譯器會(huì)將


    a=-1;


    視為


    a =- 1;



    a = a - 1;


    這會(huì)讓打算寫


    a = -1;


    的程序員感到吃驚。


    另一方面,這種老版本的C編譯器會(huì)將


    a=/*b;


    斷句為


    a =/ *b;


    盡管/*看起來像一個(gè)注釋。


    1.4 例外

    組合賦值運(yùn)算符如+=實(shí)際上是兩個(gè)記號(hào)。因此,


    a + /* strange */ = 1



    a += 1


    是一個(gè)意思。看起來像一個(gè)單獨(dú)的記號(hào)而實(shí)際上是多個(gè)記號(hào)的只有這一個(gè)特例。特別地,


    p - > a


    是不合法的。它和


    p -> a


    不是同義詞。


    另一方面,有些老式編譯器還是將=+視為一個(gè)單獨(dú)的記號(hào)并且和+=是同義詞。


    1.5 字符串和字符

    單引號(hào)和雙引號(hào)在C中的意義完全不同,在一些混亂的上下文中它們會(huì)導(dǎo)致奇怪的結(jié)果而不是錯(cuò)誤消息。


    包圍在單引號(hào)中的一個(gè)字符只是書寫整數(shù)的另一種方法。這個(gè)整數(shù)是給定的字符在實(shí)現(xiàn)的對(duì)照序列中的一個(gè)對(duì)應(yīng)的值。因此,在一個(gè)ASCII實(shí)現(xiàn)中,\'a\'和0141或97表示完全相同的東西。而一個(gè)包圍在雙引號(hào)中的字符串,只是書寫一個(gè)有雙引號(hào)之間的字符和一個(gè)附加的二進(jìn)制值為零的字符所初始化的一個(gè)無名數(shù)組的指針的一種簡短方法。


    線面的兩個(gè)程序片斷是等價(jià)的:


    printf("Hello world\\n");


    char hello[] = {
    \'H\', \'e\', \'l\', \'l\', \'o\', \' \',
    \'w\', \'o\', \'r\', \'l\', \'d\', \'\\n\', 0
    };
    printf(hello);


    使用一個(gè)指針來代替一個(gè)整數(shù)通常會(huì)得到一個(gè)警告消息(反之亦然),使用雙引號(hào)來代替單引號(hào)也會(huì)得到一個(gè)警告消息(反之亦然)。但對(duì)于不檢查參數(shù)類型的編譯器卻除外。因此,用


    printf(\'\\n\');


    來代替


    printf("\\n");


    通常會(huì)在運(yùn)行時(shí)得到奇怪的結(jié)果。


    由于一個(gè)整數(shù)通常足夠大,以至于能夠放下多個(gè)字符,一些C編譯器允許在一個(gè)字符常量中存放多個(gè)字符。這意味著用\'yes\'代替"yes"將不會(huì)被發(fā)現(xiàn)。后者意味著“分別包含y、e、s和一個(gè)空字符的四個(gè)連續(xù)存貯器區(qū)域中的第一個(gè)的地址”,而前者意味著“在一些實(shí)現(xiàn)定義的樣式中表示由字符y、e、s聯(lián)合構(gòu)成的一個(gè)整數(shù)”。這兩者之間的任何一致性都純屬巧合


    主站蜘蛛池模板: 视频一区二区中文字幕| 亚洲明星合成图综合区在线| 黑人极品videos精品欧美裸| 婷婷丁香五月中文字幕| 亚洲欧美日韩中文高清ww| 亚洲欧美日韩中文字幕在线| 国产亚洲情侣久久精品| 动漫人物差差差免费动漫在线观看| 97视频精品全国在线观看| 成人区人妻精品一区二区不卡网站| 亚洲国产亚洲片在线观看播放| 理论亚洲区美一区二区三区| 国产午夜手机精彩视频| jux434被公每天侵犯的我| 99视频精品全国在线观看| 久久人妻无码中文字幕| 久久久精品免费| 久久久久久成人毛片免费看| 欧美精品亚洲精品日韩专区| 国产一区二区在线|播放| 538在线视频观看| 天天综合天天色| 双女车车好快的车车有点污| 四虎影院永久免费观看| 在线观看午夜亚洲一区| 国模大胆一区二区三区| 国产成人午夜高潮毛片| 国产在线观看午夜不卡| 国产卡一卡二卡3卡4卡无卡视频| 国产在线一区二区三区av| 女人是男人未来1分50秒| 人人妻人人爽人人澡人人| 精品无人区乱码1区2区| 国产婷婷色综合av蜜臀av| 7777精品久久久大香线蕉| 在线免费观看视频你懂的| 中国一级毛片在线观看| 黄色小说网站在线观看| 成年女人18级毛片毛片免费| 国产国语对白露脸| 动漫人物将机机桶机机网站|