天天看點

頭檔案不是可有可無的

有些程式員用C語言寫程式的時候,不太了解頭檔案的作用。他們對編譯器提出的警告不在乎,僅以編譯、連接配接通過為目标,這可能會有潛在的危害。

頭檔案定義了資料結構和函數接口

頭檔案定義了資料結構,這大家都能體會到,因為不包含你要使用頭檔案的話,編譯根本就通不過。 頭檔案的另一個作用,定義函數接口,作用似乎沒那麼大,因為編譯、連接配接都通過了,程式也能運作了,這不就行了嗎。下面我們用 一個例子說明這個問題。

假設我們寫了一個很簡單的程式: main調用了一個函數foo:

#include <stdlib.h>
#include <stdio.h>

int main(void)
{
	int i;

	i = foo(2, 3);
	printf("foo returns %d\n", i);

	exit(0);
}

int foo(int a)
{
	return a + a;
}
           

此程式有嚴重的錯誤,但是如果我們用指令

$ gcc -c main.c
           

編譯的時候,沒有任何警告或出錯資訊。好,我們加上-Wall選項:

$ gcc -c -Wall main.c
main.c: In function `main':
main.c:8: warning: implicit declaration of function `foo'
           

這句implicit declaration of function可能是被程式員忽視最多的警告了。 好,我們繼續忽視它,接下來連接配接也能通過:

$ gcc -o ex1 main.o
           

運作也沒有問題。 但你不覺得毛骨悚然嗎? 一個嚴重的錯誤就這樣從你眼皮底下過去了。你的程式越來越複雜,這個警告混在一大堆編譯資訊裡,根本就注意不到了。 直到某一天一些奇怪的問題出現了,你開始調用各種土槍洋炮來調試程式…

其實,如果我們稍微尊重些編譯器,把函數的聲明加在main的前面,問題錯誤馬上顯現:

int foo (int a);
int main(void)
           

重新編譯

$ gcc -c -Wall main.c
main.c: In function `main':
main.c:9: error: too many arguments to function `foo'
           

這就是以錯誤的形式展現出來了,這就是函數聲明的作用。 它既告訴程式員如何調用一個函數,也讓編譯器檢查調用與函數原型是否一緻。 有些人以為連接配接器會檢查參數比對的問題,連接配接不出錯就萬事大吉了,這是不對的。你想,參數是以寄存器或壓棧的方式傳遞的。 編譯之後,參數類型和個數等資訊都已丢失,連接配接器還能幫你查錯嗎? 它隻是簡單地把名字相同的符号連接配接起來而已。

錯誤發現的越早越好

程式設計出現錯誤是不可避免的。錯誤發現的越早,修改的成本就越小。 是以原則是:盡量讓錯誤暴露出來(例如嚴格的編譯選項、測試),而不是掩蓋或忽視它。能在編譯時發現的錯誤,不要拖到運作時;能在編輯時發現的錯誤,不要拖到編譯時(許多編輯器的括号比對、代碼補齊等功能就是為了減少這樣的錯誤)。

轉載于:https://www.cnblogs.com/stemon/p/5216806.html