天天看點

Linux下的C初探(FC4)

  Linux 下的 C 初探( FC4 )   第一個 c 程式: 了解 bash 、 vi 、 gcc 、 gdb 、 g++ 、 make 、 cvs ,我們可以通過 man 指令獲得幫助,使用 which 指令檢視是否可用,如 which bash  如果回應 /bin/bash ,則 ok 了。 man printf 獲得 c 中 printf 函數的幫助。 使用 vi 編輯第一個 c 程式,在目前目錄下, vi hello.c ,按 a 鍵,進入編輯模式: # include <stdio.h> int main(void){ printf(“hello world!/n”); return 0; } 依次 Esc :wq 鍵退出 vi gcc –o hello  hello.c 或者 gcc hello.c –o hello 會産生一個名為 hello 的可執行檔案。 ./hello 指令執行這個檔案,螢幕會顯示 hello world! 我們的第一個 c 程式就完成了,這樣我們建立了學 linux c 的信心。   gcc 的使用: 接下來了解一下 gcc 的常用指令,以上面的程式為例子 gcc hello.c  預設會産生一個 a.out 的可執行檔案,使用 ls –l 指令檢視, gcc –o hello hello.c/gcc hello.c –o hello 産生一個 hello 的可執行檔案 gcc –S hello.c 産生一個 hello.S 檔案 ,我們用 ls –l 檢視知道它是可讀但不可執行,還可以知道它是個彙編語言檔案。 gcc 編譯所調用的 .h 頭檔案是在 /usr/include 目錄下面,而二進制庫檔案在 /usr/lib 下面。關于 gcc 的根多功能我們可以通過 man gcc 檢視。   Vi 的使用: vi 編輯器的功能非常強大,有三種 mode 分别是 command mode 、 Insert mode 和 last line mode , vi hello.c 預設是 command mode 是以你不能編輯,按“ i ”鍵可以進入 insert mode 插入工作,按“ Esc ”切換到 command mode 下, an “:”鍵進入 last line mode 下,按“ :w( 檔案名 ) ”儲存(檔案),按“ :wq ”儲存并退出,按“ :q! ”退出但不儲存,在 command mode 下可以按“ i ”、“ a ”、“ o ”進入 insert mode ,“ i ”是從光标目前位置開始輸入檔案,“ a ” 從目前光标所在位置的下一個位置開始輸入文字,而“ o ”是插入新的一行,從行首開始輸入文字。“ set nu ”可以設定行号。   光标移動:可以直接使用鍵盤的上下左右鍵來控制,但我們一般使用“ k ”“ j ”“ h ”“ l ”代替上下左右,按“ ctrl+b ”:螢幕往 “ 後 ” 移動一頁,“ ctrl+f ”:往 “ 前 ” 移動一頁。 “ ctrl + u ”:往 “ 後 ” 移動半頁,“ ctrl+d ” 往 “ 前 ” 移動半頁。 “ 0 ”:移到文章的開頭。“ G ”:移動到文章的最後。 “ $ ”:移動到光标所在行的 “ 行尾 ” 。 “ ^ ”:移動到光标所在行的 “ 行首 ” 。

“ w ”:光标跳到下個字的開頭,“ e ”:光标跳到下個字的字尾,“ b ” :光标回到上個字的開頭,“ #l ”:光标移到該行的第 # 個位置,如: 56l 。   删除文字:“ x ”:删除光标所在位置的 “ 後面 ” 一個字元,“ #x ”:例如,「 6x 」表示删除光标所在位置的 “ 後面 ”6 個字元。 “ X ”:删除光标所在位置的 “ 前面 ” 一個字元。“ #X ”:例如,「 20X 」表示删除光标所在位置的 “ 前面 ”20 個字元。

“ dd ”:删除光标所在行。“ #dd ”:從光标所在行開始删除 # 行。   複制和替換:“ yw ”:将光标所在之處到字尾的字元複制到緩沖區中,“ #yw ”:複制 # 個字到緩沖區 。

          “ yy ”:複制光标所在行到緩沖區,“ #yy ”:例如,「 6yy 」表示拷貝從光标所在的該行 “ 往下數 ”6 行文字。

“ p ”:将緩沖區内的字元貼到光标所在位置。所有與 “y” 有關的複制指令與 “p” 配合能完成複制與粘貼功能。 “ r ”:替換光标所在處的字元。“ R ”:替換光标所到之處的字元,直到按下“ Esc ”鍵為止。   gdb 的使用:            gdb 支援很多的指令使你能實作不同的功能。 這些指令從簡單的檔案裝入到允許你檢查所調用的堆棧内容的複雜指令 , 指令描述 :

file 裝入想要調試的可執行檔案。

kill 終止正在調試的程式。

list 執行一行源代碼但不進入函數内部。

next 執行一行源代碼但不進入函數内部。

step 執行一行源代碼而且進入函數内部。

run 執行目前被調試的程式

quit 終止 gdb

watch 使你能監視一個變量的值而不管它何時被改變。

break 在代碼裡設定斷點 , 這将使程式執行到這裡時被挂起。

make 使你能不退出 gdb 就可以重新産生可執行檔案。

shell 使你能不離開 gdb 就執行 UNIX shell 指令。

gdb 支援很多與 UNIX shell 程式一樣的指令編輯特征。 你能象在 bash 或 tcsh 裡那樣按 Tab 鍵讓 gdb 幫你補齊一個唯一的指令 , 如果不唯一的話 gdb 會列出所有比對的指令。 你也能用光标鍵上下翻動曆史指令。 gdb 使得調試程式十分有用,比如設定斷點,   make 的使用:             如果就上面的一個 hello.c 程式,我們完全沒有必要使用 make 功能,我們手工編譯就可以了,但當我們遇到很多的子產品,那麼手工來編譯就顯得不可行了,這是我們就借用 make ,但好處不僅僅在此,他隻更新修改過的檔案,并且 make 指令不會漏掉一個需要更新的檔案。 檔案和檔案間或子產品或子產品間有可能存在倚賴關系, make 指令也是依據這種依賴關系來進行維護的,我們把依賴關系寫到 makefile 檔案裡,熟悉 java 語言程式設計的就會想到 ant ,我們可以用“ make –f 檔案名”指定 makfile 檔案,但一般就把檔案取名為 makefile 。 Make 指令本身可帶有四種參數:标志、宏定義、描述檔案名和目标檔案名。其标準形式為: Make [flags] [macro definitions] [targets]                Makfile : makfile 有自己的文法規則,在 makfile 中一般說明如何編譯各個源檔案并連接配接生成可執行檔案,并要求定義源檔案之間的依賴關系。   比如,我們有個項目:其中由兩個 c 源檔案 aa.c 、 bb.c 以及庫檔案 LS 編譯生成,這兩個檔案還分别包含自己的頭檔案 a.h 、 b.h 。通常情況下, C 編譯器将會輸出兩個目标檔案 aa.o 、 bb.o 。假設 aa.c 聲明用到一個名為 abc 的檔案,但 bb.c 不用。即在 aa.c 裡有這樣的聲明: #include <abc> ,那麼建立下面的 makfile 文檔描述這些檔案之間的互相聯系 :

  1    #It is a example for describing makefile

  2    program : aa.o bb.o

  3    cc aa.o bb.o -LS -o program

  4    aa.o : aa.c a.h abc

  5    cc -c aa.c

  6    bb.o : bb.c b.h

  7    cc -c bb.c

 第一行有 # 的行為注釋行。第行指定 program 由兩個目标檔案 aa.o 、 bb.o 連結生成。第三行描述如何從 program 所依賴的檔案建立可執行檔案。接下來的 4 、 6 行分别指定兩個目标檔案,以及它們所依賴的 .c 和 .h 檔案和 abc 檔案( bb.c 沒有)。而 5 、 7 行則指定了如何從目标所依賴的檔案建立目标。

  而當 aa.c 或 a.h 檔案在編譯之後又被修改,則 make 工具可自動重新編譯 aa.o ,如果在前後兩次編譯之間, aa.c 和 a.h 均沒有被修改,而且 .o 還存在的話,就沒有必要重新編譯。這種依賴關系在多源檔案的程式編譯中尤其重要。通過這種依賴關系的定義, make 工具可避免許多不必要的編譯工作。利用 Shell 腳本也可以達到自動編譯的效果,但是, Shell 腳本将全部編譯任何源檔案,包括哪些不必要重新編譯的源檔案,而 make 工具則可根據目标上一次編譯的時間和目标所依賴的源檔案的更新時間而自動判斷應當編譯哪個源檔案。

shell 腳本和 windows 下的 .bat 檔案相當。

Makefile 檔案一般包含以下内容 :

 1 )宏定義, 2 )源檔案之間的互相依賴關系, 3 )可執行的指令。

Makefile 中允許使用簡單的宏指代源檔案及其相關編譯資訊,在 linux 中也稱宏為變量。在引用宏時隻需在變量前加 $ 符号,但值得注意的是,如果變量名的長度超過一個字元,在引用時就必須加圓括号()。宏的定義為編寫 makefile 檔案帶來很大的友善。 cvs: 如果進行團隊開發版本控制和維護是必要的 文法随筆:   x = n++;  // 先使用n的值,再使n+1;如果n==2,則x == 2,n==3 x = ++n; //先使n+1,再使用n的值;如果n==2,則x == 3,n==3 ++對n的值的作用是一樣的,但用到表達式中,作用是不一樣的。 &:可以實作屏蔽某些位或将某些位置1,c=n&0177;//保留低七位; <<:<<2;表示左移2位末端空出兩位以0填之;即作乘4; Printf(“%d %d /n”,++n,power(2,n));//錯誤,取決于機器,不同會産生不同結果,取決于n是調用power之前還是後, A[i]=i+1;//都取決于編譯器 for(a; b; c) 語句;等價與 a; while(b){語句; c; } Do {語句; } While();//先執行語句再判斷條件 Continue隻能用在循環中不能用在switch中,開始下一輪疊代, 函數之間的通訊通過參數,傳回值和全局變量實作; C語言調用 者調用一函數時,用變量取代參數,傳給函數的是變量的值而不是變量的位址;被調用函數不能影響調用者的原變量;但如果是數組名出現再函數的 參數中,則是将數組的起始位址傳給參數的,可以改變數組元素的值,數組是傳位址的, “定義”和“說明”:int sp; double val[MAX];為定義,且配置設定空間,extern int sp; extern double val[]; 說明,不配置設定空間,隻知道他們的類型;外部變量隻定義一此,而其它地方用extern 說明它;數組定義時确定大小;可以把變量的extern 說明集中在一個檔案中,使用時用#include ; 變量:内部,外部,内部變量的值不保留随調用函數退出消失 靜态變量:内部靜态變量,外部靜态變量;内部靜态變量的值保留不随調用函數退出消失,即私有,永久存儲,外部靜态變量隻屬于從它的定義處開始到檔案結束,其它檔案不能通路他們,提供了一種名字隐藏的方法,則可以用static 使得函數隻讓它的檔案知道,其它檔案不用知道,c語言中的“static”不僅意味永久性還有某程度的私有性,外部命名一樣的變量不會有沖突; 寄存器(register)變量:告知編譯器該變量經常用到,隻能用作自動變量和函數的形式參數。每個函數隻能有很少的變量可以放在寄存器中,而且僅有某些類型的變量可以是寄存器變量,寄存器變量的位址是不能取道的, 函數内不能定義函數; 外部變量和靜态變量在無明顯的賦初值時保證他們的初始化為零,初始化隻能進行依次,理論上是在編譯時進行。寄存器變量具有不确定值, 自動變量和寄存器變量在每次調用時或進入分程式時進行初始化,初值不局限于産量,還可以包括已經确定的表達式或函數調用, 預處理:#include ,包含的檔案變了,則所有與其有關的檔案都要重新編譯, *++p:先将p加1機關後再取*p中的内容 *--p :先将p減1機關再取*p中的内容 malloc():傳回整數*mallo():傳回指針 []優先與* int *day[10]:指向整數的指針組成的數組,int (*day)[10]:指向13個整數組成的數組的指針, near(16位) , far(32位), huge(32位):近,遠,特大,指針 int a[10][10]:int *b[10]:a[i][j],b[i][j]都合法,但a是真正的數組,配置設定了100個機關,b僅僅配置設定了10個指針,每個指針指向一個整型數組,如果每個整數數組是10個元素,則100個機關放整數,還得再加上10個單元放指針,有額外的開銷,但也有好處:1.通路元素是用指針間接通路而不是像數組那樣通過乘法和加法運算,即速度快,2.指針數組的每行長度不一定一樣,可以不一樣。 結構(struct)的位址和指向結構的指針:對結構隻能實作兩種運算即取結構的位址“&”&通路結構的成員“.”。不能整體利用,但指向結構的指針卻不受限制,是以結構可以和函數結合在一起了。自動的結構和自動的數組一樣不能初始化,隻有外部的或靜态結構可以初始化。 結構數組:struct key keytab[NKEYS]:兩個一樣的結構可以互相指派。 Typedef: exit(0):表示程式正常結束,非零表示異常結束。stderr和exit出錯處理 fgets(line, MAXLINE, fp):行輸入,從檔案fp中讀下個輸入行,存入字元數組line。最多可讀MAXLINE-1個字元,存入的行以“/0 ”結束 。正常結束fgets回送line,如果檔案結束則回送NULL fputs(line, fp):輸出,把一字元串(不需包含新行符)到檔案上,直接從标準I/O拷貝來的 system(“data”):系統調用,強制執行程式data輸出當天 日期&時間。 read,write ::低級I/O read(fd, buf, n); open :回送 的是檔案的描述子,而不是檔案指針(用fopen) creat(name, mode):建立檔案,mode:讀寫權限 Lseek:lseek(fd, offset, origin):随機通路

繼續閱讀