《C和指针》读书笔记第二章基本概念
寫在前面,由于學過C語言,導致想要跳躍式地翻閱《C和指針》,后來發現這實為錯誤,對于這本經典著作,要做的是從頭到尾保持體系的完整性。
《C和指針》配套代碼請移步網站:Pointers on C
作者Kenneth A. Reek的個人網站
文章目錄
- 2.1環境
- 2.1.1 翻譯
- 2.1.2 執行
- 2.2 詞法規則
- 2.2.1 字符
- 2.2.2 注釋
- 2.2.3 自由形式的源代碼
- 2.2.4 標識符
- 2.2.5 程序的形式
- 2.7 問題
2.1環境
在ANSI C的任何一種實現中,存在兩種不同的環境。第1種是翻譯環境(translation environment),在這個環境里,源代碼被轉換為可執行的機器指令。第2種是執行環境(execution environment),它用于實際執行代碼。標準明確說明,這兩種環境不必位于同一臺機器上。例如,交叉編譯器(cross compiler)就是在一臺機器上運行,但它所產生的可執行代碼運行于不同類型的機器上。操作系統也是如此。標準同時討論了獨立環境(freestanding environment),就是不存在操作系統的環境。
2.1.1 翻譯
翻譯階段由幾個步驟組成,組成一個程序的每個(有可能有多個)源文件通過編譯過程分別轉換為目標代碼(object code)。然后,各個目標文件由鏈接器(linker)捆綁在一起,形成一個單一而完整的可執行程序。鏈接器同時也會引入C函數庫種任何被該程序所用到的函數,而且它也可以搜索程序員個人的程序庫,將其中需要使用的函數也鏈接到程序中。
編譯過程本身也由幾個階段組成,首先是預處理器處理。在這個階段,預處理器在源代碼上執行一些文本操作。例如,用實際值代替由#define指令定義的符號以及讀入由#include指令包含的文件的內容。
然后,源代碼經過解析(parse),判斷它的語句的意思。第2個階段是產生絕大多數錯誤和警告信息的地方。隨后,便產生目標代碼。目標代碼是機器指令的初步形式,用于實現程序的語句。如果我們在編譯程序的命令行中加入了要求進行優化的選項,優化器(optimizer)就會對目標代碼進一步進行處理,使它效率更高。優化過程需要額外的時間,所以在程序調試完畢并準備生成正式產品之前一般不進行這個過程。至于目標代碼是直接產生的,還是先以匯編語言語句的形式存在,然后再經過一個獨立的階段編譯成目標文件,對我們來說并不重要。
一 文件名約定
c源代碼通常保存在以.c擴展名命名的文件中。由#include指令包含到c源程序的文件被稱為頭文件,通常具有擴展名.h.
至于目標文件名,不同的環境可能具有不同的性質。例如,在UNIX系統中,它們的擴展名是.o,但在MS-DOS系統中,它們的擴展名是.obj。
二 編譯和鏈接
用于編譯和鏈接c程序的特定命名在不同的系統中各不相同,但許多都和這里所描述的兩種系統差不多。在絕大多數UNIX系統中,C編譯器被稱為cc,它可以用多種不同的方法來調用。
1 編譯并鏈接一個完全包含于一個源文件的C程序:
這條命令產生一個稱為a.out的可執行文件。中間會產生一個名為program.o的目標文件,但它在鏈接過程完成后會被刪除。
2 編譯并鏈接幾個C源文件:
cc main.c sort.c lookup.c當編譯的源文件超過一個時,目標文件便不會被刪除。這就允許你對程序進行修改后,只對那些進行過改動的源文件進行重新編譯,如下一條命令所示。
3 編譯一個C源文件,并把它和現存的目標文件鏈接在一起:
cc main.o lookup.o sort.c4 編譯單個C源文件,并產生一個目標文件(本例中為program.o),以后再進行鏈接:
cc -c program.c5 編譯幾個C源文件,并為每個文件產生一個目標文件
cc -c main.c sort.c lookup.c6 鏈接幾個目標文件
cc main.o sort.o lookup.o2.1.2 執行
程序的執行過程也需要經歷幾個階段。首先,程序必須載入到內存中。在宿主環境(也就是具有操作系統的環境),這個任務由操作系統完成。那些不是存儲在堆棧中的尚未初始化的變量將在這個時候得到初始值。
然后,程序的執行便開始了。在宿主環境中,通常一個小型的啟動程序于程序鏈接在一起。它負責處理一系列日常事務,如收集命令行參數以便使程序能夠訪問它們。接著,便調用main函數。
現在,便開始執行程序代碼。在絕大多數機器里,程序將使用一個運行時堆棧,它用于存儲函數的局部變量和返回地址。程序同時也可以使用靜態內存,存儲于靜態內存中的變量在程序的整個執行過程中將一直保留它們的值。
2.2 詞法規則
一個ANSI C程序由聲明和函數組成。函數定義了需要執行的工作,而聲明則描述了函數和函數將要操作的數據類型(有時候是數據本身)。
2.2.1 字符
標準并沒有規定C環境必須使用哪種特定的字符集,但它規定字符集必須包括英文所有的大寫和小寫字母,數字0到9,以及下面這些符號:
換行符用于標志源代碼每一行的結束,當正在執行的程序的字符輸入就緒時,它也用于標志每個輸入行的結尾。 如果運行時環境需要,換行符也可以是一串字符,但它們被當作單個字符處理。字符集還必須包括空格、水平制表符、垂直制表符和格式反饋字符。這些字符加上換行符,通常被稱作空白字符,因為當它們被打印出來時,在頁面上出現的是空白而不是各種記號。
標準還定義了幾個三字母詞(trigrph),三字母詞就是幾個字符的序列,合起來表示另一個字符。 三字母詞使C環境可以在某些缺少一些必需字符的字符集上實現。
| ??( | [ |
| ??) | ] |
| ??! | | |
| ??< | { |
| ??> | } |
| ??’ | ^ |
| ??= | # |
| ??/ | \ |
| ??- | ~ |
兩個問號開頭再尾隨一個字符一般不會出現在其他表達式中,所以把三字母詞用這種形式來表示,這樣就不致引起誤解。
當你在編寫某些C源代碼時,你在一些上下文環境里想要使用某個特定的字符,卻可能無法如愿,因為該字符在這個環境里有特別的意義。 例如,雙引號“” 用于界定字符串常量,你如何在一個字符串常量內部包含一個雙引號呢? K&R C 定義了 幾個轉義序列(escape sequence) 或字符轉義(character escape),用于克服這個難題。 ANSI C 在它的基礎上又增加了幾個轉義序列。轉義序列由一個反斜杠\加上一個或多個其他字符組成。 下面列出的每個轉義序列代代表反斜杠后面的那個字符,但并未給這個字符增加特別的意義。
| \? | 在書寫連續多個問號時使用,防止它們被解釋為三字母詞 |
| \’’ | 用于表示一個字符串常量內部的雙引號 |
| \’ | 用于表示字符常量’ |
| \\ | 用于表示一個反斜杠,防止它被解釋為一個轉義序列符 |
有許多字符并不在源代碼中出現,但它們在格式化程序輸出或操縱終端顯示屏時非常有用。C語言也提供了一些這方面的轉義符,方便你在程序中使用它們。
| \a | 警告字符。它將奏響終端鈴聲或產生其他一些可聽見或可看見的信號 |
| \b | 退格鍵 |
| \f | 進紙字符 |
| \n | 換行符 |
| \r | 回車符 |
| \t | 水平制表符 |
| \v | 垂直制表符 |
| \ddd | 表示1~3個八進制數字。這個轉義符表示的字符就是給定的八進制數值所代表的字符 |
| \xddd | 用于表示十六進制數字 |
2.2.2 注釋
C語言的注釋以字符/*開始,以字符 * / 結束,中間可以包含除 */ 之外的任何字符。所有的注釋都會被預處理器拿掉,取而代之的時一個空格。因此,注釋可以出現在任何空格可以出現的地方。
下面這種嵌套是非法的
2.2.3 自由形式的源代碼
C是一種自由形式的語言,也就是說并沒有規則規定什么地方可以書寫語句,一行中可以出現多少條語句,什么地方應該留下空白以及應該出現多少空白等。唯一的規則就是相鄰的標記之間必須出現一至多個空白字符(或注釋),不然它們可能被解釋成單個標記。因此,下面語句是等價的
y=x+1;y= x + 1;y =x + 1至于下面這組語句,前3條語句是等價的,但第4條語句是非法的
int x;int x;int /*comment */ x; 合法intx; //非法對于第三條語句進行實驗
#include<stdio.h>int main() {/*/**/int /*這是個什么玩意?*/ x=1;printf("Hello,world:%d\n",x); }運行結果
Hello,world:12.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 union2.2.5 程序的形式
一個C程序可能保存于一個或多個源文件中。雖然一個源文件可以包含超過一個的函數,但每個函數都必須完整地出現于同一個源文件中。標準并沒明確規定,但一個C程序的源文件應該包含一組相關的函數,這才是較為合理的組織形式。這種做法還有一個優點,就是它使實現抽象數據類型稱為可能。
2.7 問題
3.輸出
"Blunder??!??"代碼
printf("\"Blunder?\?!??\"");總結
以上是生活随笔為你收集整理的《C和指针》读书笔记第二章基本概念的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: win10中cmd如何编译和运行c/c+
- 下一篇: 《大话数据结构》读书笔记-栈与队列