2010年12月23日 星期四

別以為你不會碰到 (2)

常常看到有人寫了一堆檔,等到要互相做連結的時候,才開始在需要用的 c 檔裡面做 extern,『要用的函數交給 extern,責任全交給編譯器』,這樣其實超危險。

要知道 c 是一個完全依賴 coder 邏輯的語言,除了 syntax 或 casting 這種低級錯誤之外,其它模陵兩可的動作,編譯器的預設立場是『我相信這是你要的結果』。

//aaa.c
int func_a (uint8_t numInput) {
  return ++numInput;
}

//bbb.c
extern int func_a(void);

int func_b (void){
  int numCatch;
  numCatch = func_a();
  printf ("holy shit %d\n", numCatch);
  return 0;
}

範例舉得很傻,但定義如下:

int* GetHash (
    int *workingBuffer, 
    char **hashArray, 
    double potential, 
    uint32_t modulus
)

還敢說不會有問題嗎?

extern 聲明參數和定義不同。這範例結果是 linker 在連結的時候不會報 error,程式執行印出來一堆從暫存器拉出來的鬼數字。

當做一個比較大型的項目,也許會拆到近萬隻源檔,這時候一些基本功就能看得出高下。

需要發佈到所有源檔裡面的函數,我會直接拖個原型在 .h,這邊就是發佈的根源,要用這隻函數,請 include header。不需要發佈的,一律上 static 鎖死在這隻檔裡,或乾脆做 inline。

第一個就是多數 compiler 抓得出錯誤,無須下額外指令,第二個就是非常好整理,畢竟用的是近 30 年的舊語言,它不是很聰明,我們就要多想想。