.h作用:
頭文件.h用於編寫變量和函數的聲明,對用戶來說起到一個接口手冊和說明的作用。在編譯過程的預編譯階段,會將所有的#include原封不動的在原地展開。因此在利用makefile的make時候如果只是修改了.h頭文件,利用make編譯的時候不會進行增量編譯,因為.h對應的.cpp或者.c並沒有改變。需要單獨刪除.h對應的.o文件再進行make。
編譯過程:
編譯過程分為:
- 預編譯階段:作用:對源文件中的宏進行展開,對#include展開等等。命令:gcc -E test.c -o test.i
- 編譯:將展開后的源文件編譯成匯編文件(匯編語言)命令:gcc -S test.i -o test.s
- 匯編:將匯編文件編譯成01機器碼的.o文件 命令:as test.s -o test.o
- 鏈接:將所有的.o文件鏈接(鏈接引用庫等等)成一個可執行程序.exe文件。gcc test.o test2.o -o test
編譯過程示例:
//lib.h int addTwo(int a, int b); //lib.c int addTwo(int a, int b) { return a+b; }
//main.c #include <stdio.h> #include "lib.h" int main() { int sum = addTwo(1, 2); printf("sum=%d\n", sum); return 0; }
gcc -E main.c -o main.i進行預編譯:
可以看到stdio.h展開了好幾百行到main.c文件中,lib.h將函數的聲明展開到了源文件中。
最后進行鏈接的命令是:
gcc main.o lib.o -o main
生成可執行程序。編譯命令中沒有.h文件,因為在預編譯過程中已經將所有的.h文件都展開到了源文件中了。
extern簡述:
extern是計算機語言中的一個關鍵字,可置於變量或者函數前,以表示變量或者函數的定義在別的文件中。提示編譯器遇到此變量或函數時,在其它模塊中尋找其定義。
每一個c文件或者cpp文件最后都會編譯為一個.o文件或者.obj文件,最后將所有的.o或.obj文件鏈接起來組成一個可執行.exe文件。在其他模塊的意思是指在鏈接的時候從其他.o或者.obj文件中找extern變量的定義。
extern代碼示例:
對變量而言,如果你想在本源文件(例如文件名A)中使用另一個源文件(例如文件名lib)的全局變量(假設為int gVar),方法有2種:
一、在文件A中聲明extern int gVar,且不包含lib的全局變量gVar。表示編譯器在鏈接的時候在另外模塊中尋找gVar的定義。即在lib.o中尋找。
//lib.h int gVar = 3; //lib.c #include "lib.h"
//A.c int main() { extern int gVar; printf("gVar=%d\n", gVar); }
程序正常輸出3;
編譯鏈接的時候需要將lib.o加上:gcc main.c lib.c -o main
二、在lib.h文件中聲明全局變量extern int gVar,在lib.c中定義變量gVar。文件A中包含這個lib.h,即可直接使用gVar變量了。
考慮下面這種情況:
//lib.h int gVar=3; int addTwo(int a, int b); //lib.c #include "lib.h" int addTwo(int a, int b) { return a+b; }
//A.h #include "lib.h" //A.c #include "A.h" int main() { int sum = addTwo(1,2); printf("sum=%d\n", sum); printf("%d\n", gVar); return 0; }
當進行gcc lib.c A.c -o A的時候會報錯。
原因是在鏈接的過程中發現重復定義了變量gVar:
修改如下:
//lib.h extern int gVar; //聲明全局變量 extern int gVar = 3;是定義 int addTwo(int a, int b); //lib.c #include "lib.h" int gVar = 3; //定義變量 int addTwo(int a, int b) { return a+b;
}
//A.h #include "lib.h" //A.c #include "A.h" int main() { int sum = addTwo(1,2); printf("sum=%d\n", sum); printf("%d\n", gVar); return 0; }
程序正常輸出。
因為在lib.h中只是聲明了gVar且為extern,所以在A.o和lib.o的鏈接過程中,A.o使用的gVar會到其他模塊lib.o中尋找gVar的定義,找到為3。
實際代碼會更加復雜,此處幾個實例簡單地剝離來討論。