參考1:C header files and compilation/linking
參考2:計算機系統基礎(一)袁春風 (符號鏈接部分)
我們現在有一個簡單的工程,有這么幾個文件
1.t1.h
extern int x;void tt();
- t1.c
#include "t1.h"int x;void tt(){x = 100;
}
- main.c
#include <stdio.h>
#include "t1.h"int main(){tt();printf("x = %d\n",x);return 0;
}
現在,我們依次來看一下
- 頭文件 和 C源文件 如何聯系在一起
- 多文件如何變成1個可執行目標文件
預處理,組合頭文件與包含它的C源文件
在32位Linux系統中。
我們執行gcc -E t1.c -o t1.i
,對源程序進行預處理,將頭文件包含進來。
所謂預處理,就是將預編譯命令處理掉,比如,把頭文件的內容拷貝到C源文件中,因此,我們就能夠理解.h和.c文件中全部變量的關系了,我們看一下生成的文件內容
# 1 "t1.c"
# 1 "<built-in>"
# 1 "<command-line>"
# 31 "<command-line>"
# 1 "/usr/include/stdc-predef.h" 1 3 4
# 32 "<command-line>" 2
# 1 "t1.c"
# 1 "t1.h" 1
extern int x;void tt();
# 2 "t1.c" 2int x;void tt(){x = 100;
}
可以看到,開始有一些記錄的信息,看起來應該是注釋,是一些說明性信息。
然后我們看到,之前頭文件的內容在這個文件里面了。如果你把它近似地看為一個源文件,你就能大概理解全局變量聲明和定義,以及不要重復定義等。
對于main.c文件的預處理,道理是一樣的
然后,我們將t1.i
和main.i
分別生成其可重定位目標文件,最后鏈接起來,就生成了可執行目標文件。
gcc -c t1.i -o t1.o # 生成可重定位目標文件
gcc -c main.i -o main.o # 生成可重定位目標文件
gcc -o main main.o t1.o # 鏈接,生成可執行目標文件
./main # 運行可執行目標文件
最后,需要說明
對于函數的聲明(頭文件聲明、外部聲明、內部聲明)與定義(內部定義、外部定義)
在c源文件中進行函數聲明,然后使用它,在鏈接的時候,這個聲明的函數(但未在該文件中定義)鏈接器會自動在其他的可重定位目標文件中尋找其定義,如果找到了就聯系起來,否則就報錯。這就意味著,所有的C源文件中的函數默認都是全局的,你可以在模塊1聲明函數a,然后調用它,在模塊2中定義函數a,之后將兩個模塊鏈接起來生成可執行文件。
好吧,每次都聲明很麻煩,所以,我們在模塊2對應的頭文件聲明,然后模塊1引入頭文件,這樣,我們就能夠進行和之前一樣的操作了,你知道的,頭文件在預處理的時候會被包含進入源文件,這樣,其實達到了和我們手動聲明一樣的效果。
如果你不想讓函數是全局的,那就加上static
,這樣,只有該源文件可以使用它了!
對于變量的定義與初始化
- 局部變量:只能在其
{ }
內使用 - static變量:只能在本模塊內使用
- 全局變量:全部都可以用
- 本模塊定義
- 外部定義
extern
對于本模塊使用的,沒得說,就是只有這個源文件能夠使用這個變量!
只討論全局變量。
- extern變量,不要初始化,只聲明即可!
- 任何初始化的全局變量,全局范圍內只能初始化1次,可以定義n次,但是最終內存空間中的,就是初始化的內個變量的位置,只有一個!
- 頭文件一般包含函數聲明,全局變量的定義似乎沒必要,或者說,不要在頭文件定義全局變量。
- 全局變量最好少出現,出現一次也就夠了,在不同編譯器下,要求不一樣。少用。 比如在Linux的gcc下,不同C源文件,可以出現多個
int x
弱符號,但是Windows的VS下就不允許。
因此說,使用全局變量,最好
- 初始化全局變量
- 只定義一次
- 其他的模塊如果要用,就聲明
extern
表示引用外部定義,而不是再聲明一個弱符號(不是不行,但是這樣的話,gcc能用,VS就不能用) - 不要在頭文件定義全局變量(頭文件被多次包含的話…得定義多少次,恐怖)
注意
函數有
- 是否聲明
- 是否定義
- 是否使用
對于任何模塊,必須先聲明,再使用,聲明之后可以不定義,因為可以外部定義,但是被聲明被使用的函數,必須有其定義。 要是聲明之后沒有使用也沒有定義,其實也行,但是最好不要這樣干,太奇怪了!
對于同一模塊,先定義再使用也可以,但是不能先使用再定義,順序很重要。
變量有
- 是否定義
- 是否初始化
- 是否使用
然后,還涉及到不同模塊之間…