1. 程式人生 > >下鄉掃盲C語言 Chapter 0

下鄉掃盲C語言 Chapter 0

但是 們的 windows 一個 我會 改變 col tput 重要

最近在看windows相關的一些書,不禁感慨,之前學習過程中經歷的很多困難實質上是缺乏一些基礎知識,而且在國內互聯網論壇上少有關於這類基礎知識的討論和講解。即使有,也大多從老舊的帖子中抄襲而成,多有錯誤和過時的地方。因此我決心寫一個成系統的掃盲文章。第一個短期的計劃是關於C語言的。我假設我的大部分讀者應該是正在上,或者剛剛修過"高級語言程序設計(C語言)"這門課程的大一,大二學生。我希望先簡單解釋一些基礎概念,常見的名詞。然後會用幾篇文章講解編寫C語言程序的幾種工具,我會把重點放在微軟的Visual Studio 2017,完全跳過VC6.0。再之後會有一兩篇文章解釋常見的編譯期錯誤和運行時錯誤,講解如何查錯,如何調試一個程序。最後可能有幾篇面向希望能進一步提高自己水平的讀者的文章。大體就是這樣了。

   0.什麽是C語言

C語言是一種高級程序語言,所謂高級程序語言,"In computer science,a high-level programming language is a programming language with strong abstraction from the details of the computer"一種高級語言是抽象的,不涉及計算機硬件細節的語言。這就使得高級語言有兩個特點,一是通過抽象減少了程序員需要思考的範圍,二是通過改變在不同平臺上的實現,使得編寫的程序可以不加修改地在不同的平臺上運行。

我們更關心第二個特點,這表示,同樣的一個helloworld程序,無論在linux還是windows系統,在amd或intel的CPU上運行,都應該在屏幕上打印一個"hello world"。在C語言剛出生時,這其實已經是一個驚人的進步,在那之前,程序員們使用匯編語言寫程序,然而匯編語言完全依賴於你使用的機器,也就是說,你在一臺機器上運行的程序,幾乎不可能在另外一臺使用了不同的硬件的電腦上運行。

疲於奔命的程序員說,要有高級語言,就有了C語言。

                        ------- Genesis 1:3

   1.C語言其實有好幾種

這裏我們來講一點歷史。

在20世紀70年代末,Dennis MacAlistair Ritchie與Kenneth Lane Thompson在貝爾實驗室設計,開發了C語言。然而後來的幾年裏,很多公司和個人開發者都不是直接使用最開始的這一版本,而是各自為方便使用而對C語言進行了修改。

1989年,為了避免各開發廠商用的C語言語法產生差異,由美國國家標準局為C語言訂定了一套完整的國際標準語法,稱為ANSI C(又稱 C89),作為C語言的標準。二十世紀八十年代至今的各種程序開發工具(編譯器,調試器,文本編輯器等)

一般都支持 ANSI C。這是被廣泛接受的一個版本,國內大部分教科書和老師的教學都基於ANSI C。

C語言還有不同的版本,但比較重要的只有三個。

ANSI C (C89) 這是被最廣泛接受的一個

C99 這個版本支持了很多新的語法,很多編譯器也實現了這個標準(例如GCC),大部分情況下使用C99新增的特性是沒問題的

C11 這個版本。。。實際上還沒有編譯器完全實現,鑒於筆者壽命有限,不再提及。

2.hello world, hello assembly, hello CST

  我想讀者們已經運行過一個hello world程序,大概像這樣

  

#include<stdio.h>
int main()
{
    printf("hello world\n");
    return 0;
}

  你可能已經單步調試過這個程序,在第三行打一個斷點,然後一行行執行,直到第五行,程序結束。

  但是,你的程序其實並不是你看到的這麽簡單,它實際上長這樣。(源代碼的部分標為黑體)

 1 #include<stdio.h>
 2 int main()
 3 {
 4 00007FF6B7BA0590  push        rbp  
 5 00007FF6B7BA0592  push        rdi  
 6 00007FF6B7BA0593  sub         rsp,0E8h  
 7 00007FF6B7BA059A  lea         rbp,[rsp+20h]  
 8 00007FF6B7BA059F  mov         rdi,rsp  
 9 00007FF6B7BA05A2  mov         ecx,3Ah  
10 00007FF6B7BA05A7  mov         eax,0CCCCCCCCh  
11 00007FF6B7BA05AC  rep stos    dword ptr [rdi]  
12     printf("hello world\n");
13 00007FF6B7BA05AE  lea         rcx,[string "hello world\n" (07FF6B7BB03E8h)]  
14 00007FF6B7BA05B5  call        printf (07FF6B7B91528h)  
15     return 0;
16 00007FF6B7BA05BA  xor         eax,eax  
17 }
18 00007FF6B7BA05BC  lea         rsp,[rbp+0C8h]  
19 00007FF6B7BA05C3  pop         rdi  
20 00007FF6B7BA05C4  pop         rbp  
21 00007FF6B7BA05C5  ret

  怎麽樣,是不是仿佛看到了克蘇魯一樣,san值狂降?

  這其實是helloworld在VS2017中,經編譯產生的匯編代碼。

  這段代碼做了三件事,

  一,保存程序上下文(context)

  二,調用printf函數(14行)

  三,恢復程序上下文(contxet)

  有些比較聰明的讀者可能已經立刻明白過來,舉手回答說,代碼的編譯就是把代碼轉換成匯編代碼,匯編代碼可以輕易地轉換成機器代碼,直接運行。這種想法已經相當接近實際情況,但如果只是單純翻譯源代碼,4-10行和18-21行的程序又是從哪兒來的呢?這段代碼其實是編譯器悄悄塞進來的,沒有這些額外的工作,程序是無法正確運行的,涉及到的知識點太多,本文中不再深入了。但在接下來的第一章,我將解釋編譯器對你的代碼做了什麽,ide和編譯器有何不同。

  但更重要的是,這個printf函數是打哪來的呢?我們都知道在C語言裏,函數要先聲明,並在某處定義出來,才能調用。

  輸入輸出的printf,scanf一族(還有sscanf,sprintf.....)被定義在stdio.h(standard input/output)中,

  關註數學運算的pow(),sqrt(),fabs()被定義在math.h中

  關於時間的time()等函數,tm等結構體被定義在time.h中

  這些頭文件屬於C語言標準,包含了具體實現的文件被稱作C語言標準庫(C Standard Library)

  在之後的第二章,將註重於說明,lib,dll,exe等文件的關系,說明C語言標準庫在我們的程序中起什麽作用。

  這只是一篇開坑的說明,所以先到此為止了。

  親愛的讀者朋友們,明年再見,啊不,下周再見。

技術分享圖片

  

下鄉掃盲C語言 Chapter 0