1. #include 命令的作用
1.1 什麼情況不使用 include
檔案void test_a()
檔案 void test_a(); // 函式宣告
void test_b()
其實,這樣的工程,可以不用使用 include 預編譯命令。
1.2 什麼情況使用 include
如果工程裡面的函式特別多,那麼按照上面的做法,則必須在每乙個 .c 檔案的開頭列出所有本檔案呼叫過的函式的宣告,這樣很不高效,而且一旦某個函式的形式發生變化,又得乙個乙個改 .c 開頭的函式宣告。
因此,#include 預編譯命令誕生。
檔案void test_a()
檔案 void test_a();
檔案 #include "a.h" // 包含含有 test_a() 函式宣告的標頭檔案
void test_b()
1.3 #include 起到什麼效果
上述**在編譯器進行預編譯的時候,遇到 #include "a.h" ,則會把整個 a.h 檔案都copy到 b.c 的開頭,因此,在實際編譯 b.c 之前,b.c 已經被修改為了如下形式:
預編譯後的臨時檔案void test_a();
void test_b()
由此可見,得到的效果和手動加 test_a() 函式宣告時的效果相同。
#tips# 在linux下,可以使用 gcc -e b.c 來檢視預編譯 b.c 後的效果。
2.1 什麼叫函式重複定義
我們經常會遇到報錯,說變數或者函式重複定義。那麼,在此,首先我舉例說明一下什麼叫函式的重複定義。
檔案void test()
檔案 void test()
那麼,在編譯的時候是不會報錯的,但是,在鏈結的時候,會出現報錯:
multiple definition of `test',因為在同乙個工程裡面出現了兩個test函式的定義。
2.2 在.h裡面寫函式實現
如果在 .h 裡面寫了函式實現,會出現什麼情況?
檔案void test_a()
檔案 #include "a.h"
void test_b()
預編譯後,會發現,b.c 被修改為如下形式:
預編譯後的臨時檔案void test_a()
void test_b()
當然,這樣目前是沒有什麼問題的,可以正常編譯鏈結成功。但是,如果有乙個 c.c 也包含的 a.h 的話,怎麼辦?
檔案#include "a.h"
void test_c()
同上,c.c 在預編譯後,也形成了如下**:
// c.c 預編譯後的臨時檔案void test_a()
void test_c()
那麼,在鏈結器進行鏈結(link)的時候,會報錯:
multiple definition of `test_a'
因此,在 .h 裡面寫函式實現的弊端就暴露出來了。但是,經常會有這樣的需求,將乙個函式設定為 內聯(inline) 函式,並且放在 .h 檔案裡面,那麼,怎樣才能防止出現上述 重複定義的報錯呢?
檔案static void test()
void test_a()
檔案 static void test()
void test_b()
編譯工程時不會報錯,但是test()函式只能被 a.c 和 b.c 中的函式呼叫,不能被 c.c 等其他檔案中的函式呼叫。
那麼,用static修飾 .h 檔案中定義的函式,會有什麼效果呢?
檔案static void test()
檔案 #include "a.h"
void test_b()
檔案 #include "a.h"
void test_c()
3. 防止標頭檔案重複包含
經常寫程式的人都知道,我們在寫 .h 檔案的時候,一般都會加上
#ifndef ***#define ***
…… #endif
這樣做的目的是為了防止標頭檔案的重複包含,具體是什麼意思呢?
它不是為了防止多個檔案包含某乙個標頭檔案,而是為了防止乙個標頭檔案被同乙個檔案包含多次。具體說明如下:
檔案static void test_a()
檔案 #include "a.h"
void test_b()
#include "a.h"
void test_c()
這樣是沒有問題的,但下面這種情況就會有問題。
檔案static void test_a()
檔案 #include "a.h"
檔案 #include "a.h"
檔案 #include "b.h"
#include "c.h"
void main()
這樣就不小心產生問題了,因為 b.h 和 c.h 都包含了 a.h,那麼,在預編譯main.c 檔案的時候,會展開為如下形式:
預編譯之後的臨時檔案static void test_a()
static void test_a()
void main()
在同乙個 .c 裡面,出現了兩次 test_a() 的定義,因此,會出現重複定義的報錯。
但是,如果在 a.h 裡面加上了 #ifndef……#define……#endif 的話,就不會出現這個問題了。
例如,上面的 a.h 改為:
檔案#ifndef a_h
#define a_h
static void test_a()
#endif
預編譯展開main.c則會出現:
預編譯後的臨時檔案#ifndef a_h
#define a_h
static void test_a()
#endif
#ifndef a_h
#define a_h
static void test_a()
#endif
void main()
在編譯main.c時,當遇到第二個 #ifndef a_h ,由於前面已經定義過 a_h,故此段**被跳過不編譯,因此,不會產生重複定義的報錯。這就是 #ifndef……#define……#endif 的精髓所在。
深入理解include預編譯原理
1.include 命令的作用 1.1 什麼情況不使用 include 檔案 void test a 檔案 void test a 函式宣告 void test b 其實,這樣的工程,可以不用使用 include 預編譯命令。1.2 什麼情況使用 include 如果工程裡面的函式特別多,那麼按照上...
深入理解include預編譯原理
1.include 命令的作用 1.1 什麼情況不使用 include 檔案 void test a 檔案 void test a 函式宣告 void test b 其實,這樣的工程,可以不用使用 include 預編譯命令。1.2 什麼情況使用 include 如果工程裡面的函式特別多,那麼按照上...
深入理解Android EventBus原理
1.定義乙個evnet public static class messageevent2.準備觀察者 宣告和注釋你的訂閱方法,可選地指定執行緒模式 subscribe threadmode threadmode.main 比如這個就指定主線程 關於型別的解釋介紹請查閱 註冊和反註冊在你的使用中,例...