日日操夜夜添-日日操影院-日日草夜夜操-日日干干-精品一区二区三区波多野结衣-精品一区二区三区高清免费不卡

公告:魔扣目錄網為廣大站長提供免費收錄網站服務,提交前請做好本站友鏈:【 網站目錄:http://www.ylptlb.cn 】, 免友鏈快審服務(50元/站),

點擊這里在線咨詢客服
新站提交
  • 網站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會員:747

毫無疑問,學習一門編程語言的基礎知識不如編寫程序有趣。但是,不知道語言的基礎知識會使你在編寫程序時缺少樂趣。

2.1 環境

在ANSI C的任何一種實現中,存在兩種不同的環境。第1種是翻譯環境(translation environment),在這個環境里,源代碼被轉換為可執行的機器指令。第2種是執行環境(execution environment),它用于實際執行代碼。標準明確說明,這兩種環境不必位于同一臺機器上。例如,交叉編譯器(cross compiler)就是在一臺機器上運行,但它所產生的可執行代碼運行于不同類型的機器上。操作系統也是如此。標準同時討論了獨立環境(freestanding environment),就是不存在操作系統的環境。你可能在嵌入式系統中(如微波爐控制器)遇到這種類型的環境。

2.1.1 翻譯

翻譯階段由幾個步驟組成,組成一個程序的每個(有可能有多個)源文件通過編譯過程分別轉換為目標代碼(object code)。然后,各個目標文件由鏈接器(linker)捆綁在一起,形成一個單一而完整的可執行程序。鏈接器同時也會引入標準C函數庫中任何被該程序所用到的函數,而且它也可以搜索程序員個人的程序庫,將其中需要使用的函數也鏈接到程序中。圖2.1描述了這個過程。

C和指針:良好的程序風格和文檔將使程序更容易閱讀和維護

 

圖2.1 編譯過程

編譯過程本身也由幾個階段組成,首先是預處理器(preprocessor)處理。在這個階段,預處理器在源代碼上執行一些文本操作。例如,用實際值代替由#define指令定義的符號以及讀入由#include指令包含的文件的內容。

然后,源代碼經過解析(parse),判斷它的語句的意思。第2個階段是產生絕大多數錯誤和警告信息的地方。隨后,便產生目標代碼。目標代碼是機器指令的初步形式,用于實現程序的語句。如果我們在編譯程序的命令行中加入了要求進行優化的選項,優化器(optimizer)就會對目標代碼進一步進行處理,使它效率更高。優化過程需要額外的時間,所以在程序調試完畢并準備生成正式產品之前一般不進行這個過程。至于目標代碼是直接產生的,還是先以匯編語言語句的形式存在,然后再經過一個獨立的階段編譯成目標文件,對我們來說并不重要。

一、文件名約定

盡管標準并沒有制定文件的取名規則,但大多數環境都存在你必須遵守的文件名命名約定。C源代碼通常保存于以.c擴展名命名的文件中。由#include指令包含到C源代碼的文件被稱為頭文件,通常具有擴展名.h。

至于目標文件名,不同的環境可能具有不同的約定。例如,在UNIX系統中,它們的擴展名是.o,但在MS-DOS系統中,它們的擴展名是.obj。

二、編譯和鏈接

用于編譯和鏈接C程序的特定命令在不同的系統中各不相同,但許多都和這里所描述的兩種系統差不多。在絕大多數UNIX系統中,C編譯器被稱為cc,它可以用多種不同的方法來調用。

1.編譯并鏈接一個完全包含于一個源文件的C程序:

     cc program.c

這條命令產生一個稱為a.out的可執行程序。中間會產生一個名為program.o的目標文件,但它在鏈接過程完成后會被刪除。

2.編譯并鏈接幾個C源文件:

     cc main.c sort.c lookup.c

當編譯的源文件超過一個時,目標文件便不會被刪除。這就允許你對程序進行修改后,只對那些進行過改動的源文件進行重新編譯,如下一條命令所示。

3.編譯一個C源文件,并把它和現存的目標文件鏈接在一起:

     cc main.o lookup.o sort.c

4.編譯單個C源文件,并產生一個目標文件(本例中為program.o),以后再進行鏈接:

     cc –c program.c

5.編譯幾個C源文件,并為每個文件產生一個目標文件:

     cc –c main.c sort.c lookup.c

6.鏈接幾個目標文件:

     cc main.o sort.o lookup.o

上面那些可以產生可執行程序的命令均可以加上“-o name”這個選項,它可以使鏈接器把可執行程序保存在“name”文件中,而不是“a.out”。在缺省情況下,鏈接器在標準C函數庫中查找。如果在編譯時加上“-lname”標志,鏈接器就會同時在“name”的函數庫中進行查找。這個選項應該出現在命令行的最后。除此之外,編譯和鏈接命令還有很多選項,請查閱你所使用的系統的文檔。

用于MS-DOS和windows的Borland C/C++ 5.0有兩種用戶界面,你可以分別選用。Windows集成開發環境是一個完整的獨立編程工具,它包括源代碼編輯器、調試器和編譯器。它的具體使用不在本書的范圍之內。MS-DOS命令行界面則與UNIX編譯器差不太多,只是有下面幾點不同:

1.它的名字是bcc。

2.目標文件的名字是file.obj。

3.當單個源文件被編譯并鏈接時,編譯器并不刪除目標文件。

4.在缺省情況下,可執行文件以命令行中第一個源或目標文件名命名,不過你可以使用“-ename”選項把可執行程序文件命名為“name.exe”。

2.1.2 執行

程序的執行過程也需要經歷幾個階段。首先,程序必須載入到內存中。在宿主環境中(也就是具有操作系統的環境),這個任務由操作系統完成。那些不是存儲在堆棧中的尚未初始化的變量將在這個時候得到初始值。在獨立環境中,程序的載入必須由手工安排,也可能是通過把可執行代碼置入只讀內存(ROM)來完成。

然后,程序的執行便開始。在宿主環境中,通常一個小型的啟動程序與程序鏈接在一起。它負責處理一系列日常事務,如收集命名行參數以便使程序能夠訪問它們。接著,便調用main函數。

現在,便開始執行程序代碼。在絕大多數機器里,程序將使用一個運行時堆棧(stack),它用于存儲函數的局部變量和返回地址。程序同時也可以使用靜態(static)內存,存儲于靜態內存中的變量在程序的整個執行過程中將一直保留它們的值。

程序執行的最后一個階段就是程序的終止,它可以由多種不同的原因引起。“正常”終止就是main函數返回[1]。有些執行環境允許程序返回一個代碼,提示程序為什么停止執行。在宿主環境中,啟動程序將再次取得控制權,并可能執行各種不同的日常任務,如關閉那些程序可能使用過但并未顯式關閉的任何文件。除此之外,程序也可能是由于用戶按下break鍵或者電話連接的掛起而終止,另外也可能是由于在執行過程中出現錯誤而自行中斷。

2.2 詞法規則

詞法規則就像英語中的拼寫規則,決定你在源程序中如何形成單獨的字符片段,也就是標記(token)。

一個ANSI C程序由聲明和函數組成。函數定義了需要執行的工作,而聲明則描述了函數和(或)函數將要操作的數據類型(有時候是數據本身)。注釋可以散布于源文件的各個地方。

2.2.1 字符

標準并沒有規定C環境必須使用哪種特定的字符集,但它規定字符集必須包括英語所有的大寫和小寫字母,數字0到9,以及下面這些符號:

! " # % ' ( ) * + , - . / :
; < > = ? [ ]  ^ _ { } | ~

換行符用于標志源代碼每一行的結束,當正在執行的程序的字符輸入就緒時,它也用于標志每個輸入行的末尾。如果運行時環境需要,換行符也可以是一串字符,但它們被當作單個字符處理。字符集還必須包括空格、水平制表符、垂直制表符和格式反饋字符。這些字符加上換行符,通常被稱作空白字符,因為當它們被打印出來時,在頁面上出現的是空白而不是各種記號。

標準還定義了幾個三字母詞(trigrph),三字母詞就是幾個字符的序列,合起來表示另一個字符。三字母詞使C環境可以在某些缺少一些必需字符的字符集上實現。這里列出了一些三字母詞以及它們所代表的字符。

  ??( [    ??< {    ??= #
  ??) ]    ??> }    ??/ 
  ??! |    ??’ ^    ??- ~

兩個問號開頭再尾隨一個字符一般不會出現在其他表達形式中,所以把三字母詞用這種形式來表示,這樣就不致引起誤解。

警告:

盡管三字母詞在某些環境中很有用,但對于那些用不著它的人而言,它實在是個令人討厭的小東西。之所以選擇??這個序列作為每個三字母詞的開始是因為它們出現的形式很不自然,但它們仍然隱藏著危險。你的腦子里一般不會有三字母詞這個概念,因為它們極少出現。所以,當你偶爾書寫了一個三字母詞時,如下所示:

 

printf("Delete file (are you really sure??): " );

結果輸出中將產生]字符,這無疑會令你大吃一驚。

當你編寫某些C源代碼時,你在一些上下文環境里想使用某個特定的字符,卻可能無法如愿,因為該字符在這個環境里有特別的意義。例如,雙引號 " 用于定界字符串常量,你如何在一個字符串常量內部包含一個雙引號呢?K&R C定義了幾個轉義序列(escape sequence)或字符轉義(character escape),用于克服這個難題。ANSI C在它的基礎上又增加了幾個轉義序列。轉義序列由一個反斜杠加上一或多個其他字符組成。下面列出的每個轉義序列代表反斜杠后面的那個字符,但并未給這個字符增加特別的意義。

? 在書寫連續多個問號時使用,防止它們被解釋為三字母詞。

" 用于表示一個字符串常量內部的雙引號。

' 用于表示字符常量 '。

\ 用于表示一個反斜杠,防止它被解釋為一個轉義序列符。

有許多字符并不在源代碼中出現,但它們在格式化程序輸出或操縱終端顯示屏時非常有用。C語言也提供了一些這方面的轉義符,方便你在程序中包含它們。在選擇這些轉義符的字符時,特地考慮了它們是否有助于記憶它們代表的字符的功能。

K&R C:

下面的轉義符中,有些標以“†”符號,表示它們是ANSI C新增的,在K&R C中并未實現。

 

a † 警告字符。它將奏響終端鈴聲或產生其他一些可聽見或可看見的信號。

b 退格鍵。

f 進紙字符。

n 換行符。

r 回車符。

t 水平制表符。

v † 垂直制表符。

ddd ddd表示1~3個八進制數字。這個轉義符表示的字符就是給定的八進制數值所代表的字符。

xddd † 與上例類似,只是八進制數換成了十六進制數。

注意,任何十六進制數都有可能包含在xddd序列中,但如果結果值的大小超出了表示字符的范圍,其結果就是未定義的。

2.2.2 注釋

C語言的注釋以字符/*開始,以字符*/結束,中間可以包含除*/之外的任何字符。在源代碼中,一個注釋可能跨越多行,但它不能嵌套于另一個注釋中。注意,/*或*/如果出現在字符串字面值內部,就不再起注釋定界符的作用。

所有的注釋都會被預處理器拿掉,取而代之的是一個空格。因此,注釋可以出現于任何空格可以出現的地方。

警告:

注釋從注釋起始符/開始,到注釋終止符/結束,其間的所有東西均作為注釋的內容。這個規則看上去一目了然,但對于編寫了下面這段看上去很無辜的代碼的學生而言,情況就不一定如此了。你能看出來為什么只有第1個變量才被初始化嗎?

x1=0; /***********************
x2=0; **Initialize the   **
x3=0; **counter variables. **
x4=0; ***********************/

警告:

注意中止注釋用的是*/而不是*?。如果你擊鍵速度太快或者按住shift鍵的時間太長,就可能誤輸入為后者。這個錯誤在指出來以后是一目了然,但在現實的程序中這種錯誤卻很難被發現。

2.2.3 自由形式的源代碼

C是一種自由形式的語言,也就是說并沒有規則規定什么地方可以書寫語句,一行中可以出現多少條語句,什么地方應該留下空白以及應該出現多少空白等[2]。唯一的規則就是相鄰的標記之間必須出現一至多個空白字符(或注釋),不然它們可能被解釋為單個標記。因此,下列語句是等價的:

y=x+1;
y = x + 1;
y = x
+
1

至于下面這組語句,前3條語句是等價的,但第4條語句卻是非法的:

int
x;

int  x;

int/*comment*/x;

intx;

這種代碼書寫的極度自由有利有弊。很快你就將聽到一些關于這個話題的肥皂盒哲學。

2.2.4 標識符

標識符(identifier)就是變量、函數、類型等的名字。它們由大小寫字母、數字和下劃線組成,但不能以數字開頭。C是一種大小寫敏感的語言,所以abc、Abc、abC和ABC是4個不同的標識符。標識符的長度沒有限制,但標準允許編譯器忽略第31個字符以后的字符。標準同時允許編譯器對用于表示外部名字(也就是由鏈接器操縱的名字)的標識符進行限制,只識別前六位不區分大小寫的字符。

下列C語言關鍵字是被保留的,它們不能作為標識符使用:

auto    do     goto     signed     unsigned
break   double  if       sizeof     void
case    else   int      static     volatile
char    enum   long     struct     while
const   extern  register switch
continue float   return   typedef
default  for    short    union

2.2.5 程序的形式

一個C程序可能保存于一個或多個源文件中。雖然一個源文件可以包含超過一個的函數,但每個函數都必須完整地出現于同一個源文件中[3]。標準并沒有明確規定,但一個C程序的源文件應該包含一組相關的函數,這才是較為合理的組織形式。這種做法還有一個額外的優點,就是它使實現抽象數據類型成為可能。

2.3 程序風格

這里按順序列出了一些有關編程風格的評論。像C這種自由形式的語言很容易產生邋遢的程序,就是那種寫起來很快很容易但以后很難閱讀和理解的程序。人們一般憑借視覺線索進行閱讀,所以你的源代碼如果井然有序,將有助于別人以后閱讀(閱讀的人很可能就是你自己)。程序2.1就是一個例子,雖然有些極端,但它說明了這個問題。這是一個可以運行的程序,執行一些多少有點用處的功能。問題是,你能明白它是干什么的嗎[4]?更糟的是,如果你要修改這個程序,該從何處著手呢?盡管,如果時間充裕,經驗豐富的程序員能夠推斷出它的意思,但恐怕很少會有人樂意這么干。把它扔在一邊,自己從頭寫一個要方便快速得多。

#include <stdio.h>
main(t,_,a)
char *a;
{return!0<t?t<3?main(-79,-13,a+main(-87,1-_,
main(-86, 0, a+1 )+a)):1,t<_?main(t+1, _, a ):3,main ( -94, -27+t, a
)&&t == 2 ?_<13 ?main ( 2, _+1, "%s %d %dn" ):9:16:t<0?t<-72? main(_,
t,"@n'+,#'/*{}w+/w#cdnr/+,{}r/*de}+,/*{*+,/w{%+,/w#q#n+,/#{l,+,/n{n+
,/+#n+,/#;#q#n+,/+k#;*+,/'r :'d*'3,}{w+K w'K:'+}e#';dq#'l q#'+d'K#!/
+k#;q#'r}eKK#}w'r} eKK{nl}'/#;#q#n'}{}#}w'}{}{nl}'/+#n';d}rw' i;# }{n
l}!/n{n#'; r{#w'r nc{nl}'/#{l,+'K {rw' iK{;[{nl}'/w#q#
n'wk nw' iwk{KK{nl}!/w{%'l##w#' i; :{nl}'/*{q#'ld;r'} {nlwb!/*de}'c 
;;{nl'-{}rw}'/+,} ##'*}#nc,',#nw]'/+kd'+e}+;
#'rdq#w! nr'/ ') }+}{rl#'{n' '}# }'+}##(!!/")
:t<-50?_==*a ?putchar(a[31]):main(-65,_,a+1):main((*a == '/')+t,_,a
+1 ):0<t?main ( 2, 2 , "%s"): *a=='/'|| main(0, main(-61,*a, "!ek;dc 
i@bK'(q)-[w]*%n+r3#l,{} :nuwloca-O; m .vpbks,fxntdCeghiry"),a+1);}

程序2.1神秘程序        

mystery.c

提示:

不良的風格和不良的文檔是軟件生產和維護代價高昂的兩個重要原因。良好的編程風格能夠大大提高程序的可讀性。良好的編程風格的直接結果就是程序更容易正確運行,間接結果是它們更容易維護,這將節省大筆資金成本。

本書的例子程序使用的風格是通過合理使用空格以強調程序的結構。我在下面列出了這個風格的幾個特征,并說明為什么使用它們。

1.空行用于分隔不同的邏輯代碼段,它們是按照功能分段的。這樣,讀者一眼就能看到某個邏輯代碼段的結束,而不必仔細閱讀每行代碼來找出它。

2.if和相關語句的括號是這些語句的一部分,而不是它們所測試的表達式的一部分。所以,我在括號和表達式之間留下一個空格,使表達式看上去更突出一些。函數的原型也是如此。

3.在絕大多數操作符的使用中,中間都隔以空格,這可以使表達式的可讀性更佳。有時,在復雜的表達式中,我會省略空格,這有助于顯示子表達式的分組。

4.嵌套于其他語句的語句將縮進,以顯示它們之間的層次。使用Tab鍵而不是空格,你可以很容易地將相關聯的語句整齊排列。當整頁都是程序代碼時,使用足夠大的縮進有助于程序匹配部分的定位,只使用兩到三個空格是不夠的。

有些人避免使用Tab鍵,因為他們認為Tab鍵使語句縮進得太多。在復雜的函數里,嵌套的層次往往很深,使用較大的Tab縮進意味著在一行內書寫語句的空間就很小了。但是,如果函數確實如此復雜,你最好還是把它分成幾個函數,可以使用其他函數來實現原先嵌套太深的部分語句。

5.絕大部分注釋都是成塊出現的,這樣它們從視覺上在代碼中很突出。讀者可以更容易找到和跳過它們。

6.在函數的定義中,返回類型出現于獨立的一行中,而函數的名字則在下一行的起始處。這樣,在尋找函數的定義時,你可以在一行的開始處找到函數的名字。

在你研究這些代碼例時,你還將看到很多其他特征。其他程序員可以選擇他們喜歡的個人風格。你到底采用這種風格還是選擇其他風格其實并不重要,關鍵是要始終如一地堅持使用同一種合理的風格。如果你始終保持如一的風格,任何有一定水平的讀者都能較為容易地讀懂得你的代碼。

2.4 總結

一個C程序的源代碼保存在一個或多個源文件中,但一個函數只能完整地出現在同一個源文件中。把相關的函數放在同一個文件內是一種好策略。每個源文件都分別編譯,產生對應的目標文件。然后,目標文件被鏈接在一起,形成可執行程序。編譯和最終運行程序的機器有可能相同,也可能不同。

程序必須載入到內存中才能執行。在宿主式環境中,這個任務由操作系統完成。在自由式環境中,程序常常永久存儲于ROM中。經過初始化的靜態變量在程序執行前能獲得它們的值。你的程序執行的起點是main函數。絕大多數環境使用堆棧來存儲局部變量和其他數據。

C編譯器所使用的字符集必須包括某些特定的字符。如果你使用的字符集缺少某些字符,可以使用三字母詞來代替。轉義序列使某些無法打印的字符得以表達,例如在程序中包含某些空白字符。

注釋以/*開始,以*/結束,它不允許嵌套。注釋將被預處理器去除。標識符由字母、數字和下劃線組成,但不能以數字開頭。在標識符中,大寫字母和小寫字母是不一樣的。關鍵字由系統保留,不能作為標識符使用。C是一種自由形式的語言。但是,用清楚的風格來編寫程序有助于程序的閱讀和維護。

2.5 警告的總結

1.字符串常量中的字符被錯誤地解釋為三字母詞。

2.編寫得糟糕的注釋可能會意外地中止語句。

3.注釋的不適當結束。

2.6 編程提示的總結

良好的程序風格和文檔將使程序更容易閱讀和維護。

本文摘自《C和指針》

C和指針:良好的程序風格和文檔將使程序更容易閱讀和維護

 

本書提供與C語言編程相關的全面資源和深入討論。本書通過對指針的基礎知識和高級特性的探討,幫助程序員把指針的強大功能融入到自己的程序中去。

全書共18章,覆蓋了數據、語句、操作符和表達式、指針、函數、數組、字符串、結構和聯合等幾乎所有重要的C編程話題。書中給出了很多編程技巧和提示,每章后面有針對性很強的練習,附錄部分則給出了部分練習的解答。

本書適合C語言初學者和初級C程序員閱讀,也可作為計算機專業學生學習C語言的參考。

分享到:
標簽:指針
用戶無頭像

網友整理

注冊時間:

網站:5 個   小程序:0 個  文章:12 篇

  • 51998

    網站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會員

趕快注冊賬號,推廣您的網站吧!
最新入駐小程序

數獨大挑戰2018-06-03

數獨一種數學游戲,玩家需要根據9

答題星2018-06-03

您可以通過答題星輕松地創建試卷

全階人生考試2018-06-03

各種考試題,題庫,初中,高中,大學四六

運動步數有氧達人2018-06-03

記錄運動步數,積累氧氣值。還可偷

每日養生app2018-06-03

每日養生,天天健康

體育訓練成績評定2018-06-03

通用課目體育訓練成績評定