C 語言的演進, K&R (1978) -> ANSI C89 (1989) -> ISO C99 (1999) -> C11 (2011)
POSIX (Portable Operating System Interface of UNIX) 標準, 由 IEEE 制定類 Unix 的作業系統在實作上共通的基礎 (API 的關聯、Shell的運作、命令列工具的的執行相關規範, 跟本篇最大的關聯是符合 POSIX 標準的系統, 也包含了提供 C 語言的編譯器)。
##介紹內容 Basic Tool: GDB、Valgrind、gprof、make、pkg-config、doxygen Autotools: Autoconf、Automake、libtool Useful Lib: libcURL、libGlib、libGSL、libSQLite3、libXML2
###編譯階段 使用 pkg-config 顯示出使用該lib需要的 include、link 參數
pkg-config --libs [lib name]
pkg-config --cflags [lib name]
一般在編譯時, 使用額外 lib 在編譯時所需的下參數
gcc -I[header path] -L[library path] -l[library name]
-I: 將路徑加入 include header 搜尋 path
-L: 將路徑加入 Library 搜尋 path
-l: 指定連結函式庫
-D: 等同於 define symbol (ex. -Dxxx)
可以搭配 pkg-config 使用 (但並非所有 lib 都有對 pkg-config 註冊)
gcc `pkg-config --cflags --libs [lib name]` -o [output name] [source file name]
##執行期間的 Link (Share Library)
P=program_name
OBJECT=
CFLAGS= -g -Wall -O3
LDLIBS=
CC=C99
$(P): $(OBJECT)
(Makefile 範例)
CFLAGS="-g -Wall" make // 針對 make 及 子程序設定環境變數 (上述方法2)
make CFLAGS="-g -Wall" // 設定 makefile 變數 (上述方法3)
make -p > rule.txt
可以查看 rule.txt 瞭解 make 的隱含規則
##Manual Page
Manual Page
GDB vs LLDB
set $ptr=&x[3] //expr int* $ptr = &x[3]
p *($ptr++)
之後再重複按 Enter 會執行前一動指令, 此技巧可走訪陣列, 甚至套用 link-list
##p $
$ 可表示前一次輸出變數存放的值, 但這邊 LLDB 測試無效
在 .gdbinit 中可以 define macro 來整理複雜資料結構的輸出
##Profiling Compile option 加上 -pg 會為 gprof 準備程式, 指令 gprof binary > profile 即可開始記錄, 結束後再打開 profile 看 log。 mac 上的分析可以參考 StackOverflow 提到的 Instruments
##Valgrind 可以使用 Valgrind 偵測記憶體的使用錯誤(例子省略)
##Unit Test 使用 Glib 內建的 tool 來實作(省略), 求覆蓋率可透過在 Compile option 加上 - fprofile-arcs -ftest-coverage -O0, 在執行程式後下指令 gcov program.gcda 可顯示執行行數的百分比, 另外 program.c.cov 會顯示被測試到的次數
##Doxygen 使用 Doxygen 來產生文件, 比起在程式碼中添加的說明, 搭配 Graphviz 產生的各類圖表在 trace code 幫助更大。
##Autotool 章節 在打包程式的部分目前常見的還有 CMake 可以使用, autotool的部分等以後有時間再回過頭來看吧... Ker Ker
##Git 版本控管章節 Git 中文參考資料
##類似書中範例的參考 Wrapping C/C++ for Python
##變數的存取 Reference
在記憶體的使用上, 傳遞 struct 時會整個被複製出去, 但 array 僅會傳遞別名 (指向相同的記憶體空間)。
另外, Array 目前已可提供執行期才決定大小 (透過 run time 得知的值來宣告 array), 並且不用手動 free。
##Point
ptr[0] = *(ptr+0) // 這邊僅表示左右兩者相等, 非賦值
(但是 void 的 point 是無法以陣列的方式取值, 因為缺少了型別無法計算位移量)。
###NaN N
ot-A
-N
umber, 使用 NaN 作為例外回傳值, 另外 NaN 具備的特性, 即使 NaN == NaN 也會回傳 false, 只能用 isnan() 來檢查。
NaN 的值可透過 0/0. 來得到 (0/0 會產生錯誤, 因為整數無法表示 NaN)。
##介紹容易犯錯的章節 ###Macro 在巨集的外部需加上大括號, 好處是可限制展開內容的變數生存空間, 也可降低展開後造成問題的風險。
gcc -E [source file name]
加上-E
option 之後只會執行前置處理器的部分, 並從標準輸出中印出結果, 可搜尋巨集擴展的部分來除錯。
##前置處理器中的小技巧
##const
前後相鄰的 int 與 const 可以互換, 意義仍不變。
struct 內的變數, 透過將 pointer 傳出之後仍舊無法受到 const 的保護, 需特別注意。
int *ptr;
int const **constptr = &ptr
int const const_var = 10;
*constprt = &const_var // 等同 ptr = &const_var
*prt = 20 // 等同於改變了 const_var 的值
範例顯示透過指標操作 const 需要小心
define test(i, ...) for(int index=0; index<i; i++) {__VA__ARGS__}
int iArray[] = {0, 1, 2, 3}; //賦值用
function( (iArray[]){0,1,2,3} ) //傳遞用
struct stTest
{
int first;
int second;
};
struct stTest temp = {.first=1};
int list[5] = {[3]=4, [4]=5};
指定初始子, 未指定會賦值 0
__attribute__((format(printf,m,n)))