Download presentation
Presentation is loading. Please wait.
1
編譯環境介紹
2
最常用的文書編輯器vi及vim
3
安裝vim vi和vim的最大不同在於vim支 援「多顏色」的編輯環境,因 此我們選用vim
vi幾乎是所有Linux都提供的編 輯器,請同學自學 第一次執行vim系統會說沒有 這個軟體,請依照螢幕只是輸 入 sudo apt-get install vim
4
使用圖形化介面安裝vim Ubuntu內建Ubuntu software center,可以使用圖形化介面 安裝程式
標準的vim是純文字介面, Ubuntu software center允許我 們安裝圖形化介面的vim 你們喜歡圖形化介面或純文字 介面呢?
5
先使用容易上手的「圖形化」vim 輸入「a」這個字母代表我們 要開始編譯 輸入程式碼 將檔案存成~/sp/hello.c
儲存的方式是按下「ESC」然後 打w hello.c 這時候你可以看到你的程式碼的 關鍵字變色了
6
一些設定 選擇下列選項,讓vim協助我 們程式碼的排版,並列出行號 Toggle Line Numbering
Toggle auto-indent Toggle C-indenting
7
使用vim的「快捷鍵」
8
為何要學習「快捷鍵」 學會快捷鍵以後,編輯程式碼的速度可以變得更快 如果你使用的vim沒有圖形化介面,那麼你只能使用「快捷鍵」
9
Vim的編輯模式 編輯模式 按下i,o,a進入編輯模式,ESC退回一般模式 一般模式 指令模式 按下「:」進入命令列模式,ESC退回一般模式
10
vim一般模式常用功能 瀏覽 搜尋 上下左右鍵,移動游標 ctr-f, ctr-b,向下或向上移動一頁
0或「home」移到該列的第一個字元,$或「end」移到該列最後一個字 元 G移到最後一列,gg移到第一列 搜尋 「/word」向下尋找word這個字 「?word」向上尋找word這個字 n繼續尋找
11
vim一般模式常用功能 刪除、複製、貼上 x, X:小x向後刪除一個字元,大X向前刪除一個字元 dd:刪除整個列
ndd:n是一個數字,例如20,20dd代表向下刪除20列 yy:複製游標所在的那一行 nyy:複製游標所在的底下n行 p:將複製的資料,於游標的下一行開始貼上 u:復原前一個動作 [ctr]+r:重做上一個動作
12
一般指令模式 i:從目前游標所在位置開始插入(輸入) 「ESC」:退出一般模式
13
指令模式 :w,寫入檔案 :w!,強制寫入檔案 :q,離開vim :q!,強制離開vim :wq,寫入檔案並離開
14
寫程式碼常用指令 Ctr-n:自動補上該字
15
使用圖形化編輯器
16
選擇哪一個圖形化編輯器呢 - Geany
17
安裝
18
Geany的對程式碼編輯的支援 自動完成功能 參數提示功能
19
Geany的編譯環境
20
gcc 與 gdb
21
gcc常用的編譯參數 gcc xxx.c gcc xxx.c -o exec gcc xxx.c -O3 gcc xxx.c –ansi
xxx.c必需內含main function,編譯以後產生的執行檔檔名為a.out gcc xxx.c -o exec xxx.c必需內含main function,編譯以後產生的執行檔檔名為exec gcc xxx.c -O3 xxx.c必需內含main function,啟動最佳化,O後面可以為1, 2, 3 gcc xxx.c –ansi xxx.c必須使用標準的ANSI C撰寫,所有gcc的擴充語法都不可以使用 gcc xxx.c –g 產生的執行檔案可以用gdb除錯 gcc xxx.c -pg 產生的執行檔案可以用gprofile量測效能
22
一個簡單但錯誤的例子 #include <stdio.h> #include <stdlib.h> int main () { int *p; /*指標未給初始值*/ scanf("%d", p); printf("%d", *p); }
23
編譯並除錯 $gcc pointer.c –g –o pointer $gdb ./pointer gdb ./pointer /*一堆版權宣告訊息*/ (gdb)b main /*在main函數設定break point*/ Breakpoint 1 at 0x4005a5: file pointer.c, line 6. (gdb)r /*開始執行*/ Starting program: /home/shiwulo/sp/pointer Breakpoint 1, main () at pointer.c:6 6 scanf(“%d”, p); /*程式碼停在main函數的第一行*/ 請注意,紅色字體為提醒文字,並非Linux所輸出的文字
24
編譯並除錯 (gdb)n 1 /*你的執行檔pointer等著你輸入一個字*/ Program received signal SIGSEGV, Segmentation fault. 0x00007ffff7a6c742 in _IO_vfscanf_internal (s=<optimized out>, format=<optimized out>, at vfscanf.c: vfscanf.c: No such file or directory. /*gdb告訴你發生segmentation fault*/
25
編譯並除錯 (gdb)bt #0 0x00007ffff7a6c742 in…at vfscanf.c:1857 #1 0x00007ffff7a72ed9 in … at isoc99_scanf.c:37 #2 0x bb in main () at pointer.c:6 /*bt可以看到目前的呼叫堆疊*/ /*從上述的訊息可以知道pointer.c的第6行呼叫isoc99_scanf.c,isoc99_scanf.c呼叫vfscanf.c,並且在vfsacnf.c的1857行發生錯誤,由於我們相信libC應該不會有bug,所以bug很有可能發生在pointer.c的第6行*/ 請注意…代表我刪除了一些沒用的訊息
26
編譯並除錯 vfscanf 目前在此函數 Isoc99_scanf (gdb) up #1 0x00007ffff7a72ed9 … at isoc99_scanf.c:37 37 isoc99_scanf.c: No such file or directory. #2 0x bb in main () at pointer.c:6 6 scanf(“%d", p); (gdb) /*注意,還未執行up前,gdb在「呼叫堆疊」裡面是位於vfscanf,因此必須執行二次的up才會到pointer.c*/ (gdb) print p /*print可以印出某個變數的值*/ $1 = (int *) 0x0 /*到這裡我們可以確定這個程式碼是因為指標未給初始值造成錯誤*/ pointer 二次up後到此函數
27
編譯並除錯 常用的gdb功能 help 印出gdb的功能與解釋 commends定義簡短指令 b 設定breakpoint
watch觀察某一個變數是否被修改 bt 看目前的呼叫堆疊 l 看目前的程式碼 s 單步執行(遇到函數會跳進去追 蹤) n 單步執行(遇到函數不會跳進 去追蹤) p 印出某個變數的值 r 開始執行 info 會印出許多有用的東西
28
make:簡化常用的編譯指令
29
語法 target: source1.o source2.o… /*如果source1.o, source2.o其中有*/ gcc source1.o source2.o –o target /*一個比target還要新*/ /*就會執行gcc*/ clean: /*無預設條件*/ rm *.o
30
實例 pointer: pointer.c /*只有當pointer.c的時間比pointer還新時*/ gcc pointer.c -O3 -o pointer /*才會執行gcc指令*/ hello: hello.c gcc hello.c -O3 -o hello table: table.c gcc table.c -O3 -o table clean: /*只要執行clean就一定會執行remove*/ rm pointer rm hello rm table
31
更複雜一點點的例子 all: pointer hello table /*打make all時,只要xxx.c有任何變動,其*/ touch all /*對應的gcc會重新編譯該檔案*/ pointer: pointer.c gcc pointer.c -O3 -o pointer hello: hello.c gcc hello.c -O3 -o hello table: table.c gcc table.c -O3 -o table clean: rm pointer rm hello rm table
32
更複雜一點點的例子 all: pointer hello table /*打make all時,只要xxx.c有任何變動,其*/ touch all /*對應的gcc會重新編譯該檔案*/ pointer: pointer.c touch pointer /* hello: hello.c touch hello table: table.c touch table clean: rm pointer rm hello rm table
33
GNU C內建的效能衡量工具 gprofile
34
範例程式 如右圖,一個表格(table), 分別計算欄(col)的總和及列 (row)的總和 程式碼的程式碼如下頁所示
35
程式碼 將table初始化 列印結果 以row major方式計算 主函數,呼叫各個子函數 以col major方式計算
#define size long table[size][size]; long col[size]; long row[size]; void initTable() { int i, j; for (i=0; i< size; i++) for (j=0; j<size; j++) table[i][j]=random(); } void sumCol() { for (i=0; i<size; i++) col[j] = table[i][j]; void sumRow() { row[i] = table[i][j]; void printResult() { int i; printf(" RAW\tCol\n"); printf("%8ld\t%8ld\n", row[i], col[i]); int main() { printf("hello\n"); initTable(); sumRow(); sumCol(); printResult(); return 0; 將table初始化 列印結果 以row major方式計算 主函數,呼叫各個子函數 以col major方式計算
36
編譯的命令,及gprof命令 gcc table.c -pg -o table /*編譯,注意,要加入-pg*/ ./table /*執行,會自動產生gmon.out*/ gprof -b table gmon.out /*產生報表,如下頁所示*/
37
gprof產生的報表 主要產生 各個函數的執行時間 call graph(呼叫圖)
38
執行時間 sumCol的執行時間是42.71% sumRow的執行時間是28.48%
雖然前述二者做的加法次數一 樣。由這裡可以看出row major 會比較快! 較快的原因可以用perf觀察 initTable花了29.66%的時間
39
呼叫圖 由左圖可以看到main分別呼叫 了四個函數。 也可以觀察到呼叫這四個函數 佔了總體多少時間
Similar presentations