TechBridge 技術共筆部落格

var topics = ['Web前後端', '行動網路', '機器人/物聯網', '數據分析', '產品設計', 'etc.']

C++ Header Guard 簡介


前言

C++ 的 header guard (中文譯作表頭哨兵,聽起來超帥) 是在開源/大型專案中常常用到的功能,所以如果想要踏入開源專案的世界,看到 header guard 就覺得親切熟悉,絕對可以幫助你更把心思放在體會到這些開源程式碼的美!

而且這個例子正巧是有朋友去面試美國某間新創公司時,實際被問到的問題,所以才興起想要動筆寫下這篇文章的念頭。畢竟很多小地方有沒有真正弄通是技術實力紮不紮實的重要指標!

我剛剛隨便選了一個 C++ 的開源專案 (Point Cloud Library) 的 header 檔,裡面就有用到

1
2
3
4
5
6
7
8
9
10
#ifndef PCL_PEOPLE_PERSON_CLASSIFIER_H_
#define PCL_PEOPLE_PERSON_CLASSIFIER_H_

#include <pcl/people/person_cluster.h>
#include <pcl/people/hog.h>

...

#include <pcl/people/impl/person_classifier.hpp>
#endif /* PCL_PEOPLE_PERSON_CLASSIFIER_H_ */

預處理器簡介

首先我們需要對 header file 的使用有個初步的認識,這就不能不介紹一下預處理器。我們都知道,要使用 header file 就是要在程式碼中 #include 它,而 #include 就是預處理器的一部分。

預處理器存在的目的是為了處理程式碼內的文本,例如 header file 的內容,之所以稱做 “預” 處理器是因為他在編譯氣執行之前就會先做事了。以 header file 的例子來說,預處理器會以 header file 的內容取代 #include 那一行。

那為何需要 header guard

原因是,header file 也常常需要 #include 其他 header file,例如寫程式時可能會寫到如下的程式碼:

main.cpp:

1
2
3
4
#include <string>
#include "myHeader1.h"
#include "myHeader2.h"
...

myHeader1.h:

1
2
#include <string>
...

如果在 myHeader1.h 裡面也需要用到 string,那可想而知經過預處理器的處理後,main.cpp 裡面就會有兩次 #include <string>,但這種情況根本超級常見啊,我們總不可能都去檢查過 myHeader1.h、myHeader2.h 跟他們 include 的所有 header file 再決定自己要不要 #include <string> 吧。所以就要有個機制,讓 header file 即便被 include 多次,也不會有其內定義的 classes 和 objects 被多次定義。而通常,我們就是用 header guard 來做這件事。

header guard 怎麼運作

這時候就讓我們再回過頭來看看前言提到的例子:

1
2
3
4
5
6
7
8
9
10
#ifndef PCL_PEOPLE_PERSON_CLASSIFIER_H_
#define PCL_PEOPLE_PERSON_CLASSIFIER_H_

#include <pcl/people/person_cluster.h>
#include <pcl/people/hog.h>

...

#include <pcl/people/impl/person_classifier.hpp>
#endif /* PCL_PEOPLE_PERSON_CLASSIFIER_H_ */

這邊使用到的是名為預處理器變數(preprocessor variables)的東西,在此例中為 PCL_PEOPLE_PERSON_CLASSIFIER_H_,而預處理器變數只有兩種狀態;已定義和未定義。所以上面的寫法就是用 #ifndef 來判斷是否已經定義過 PCL_PEOPLE_PERSON_CLASSIFIER_H_,如果沒有,那就先定義 PCL_PEOPLE_PERSON_CLASSIFIER_H_,然後才 #include 後面的東西。

看到這邊讀者們應該不難推敲,只要在需要 #include 的地方都加上類似的預處理器變數檢查,那就只有在預處理器變數還沒被定義時才會 #include,一旦被定義過了,就不會再重複定義了。

再回過頭來,如果你去看 string.h 的內容,你就會看到:

1
2
3
#ifndef _STRING_H_
#define _STRING_H_ 1
...

這樣一切就都串起來了!

總結

以前在學生時代學習程式語言的時候,常常會有學了某個東西不知道好用在哪裡的感覺,header guard 就是一個好例子。透過開源專案,我們很容易欣賞到某個功能的美,也希望大家看完這篇之後,每次看到 header guard 都能感覺世界真美好 XD

關於作者:
@pojenlai 演算法工程師,對機器人跟電腦視覺有>少許研究,最近在學習看清事物的本質與改進自己的觀念

喜歡我們的文章嗎?歡迎分享按讚給予我們支持和鼓勵!





訂閱 TechBridge Weekly 技術週刊,每週發送最精華的技術開發、產品設計的資訊給您



TechBridge Weekly 技術週刊編輯團隊

TechBridge Weekly 技術週刊團隊是一群對用技術改變世界懷抱熱情的團隊。本技術共筆部落格初期專注於Web前後端、行動網路、機器人/物聯網、資料科學與產品設計等技術分享。This is TechBridge Weekly Team Tech Blog, which focus on web, mobile, robotics, IoT, Data Science technology sharing.

關於我們 / 技術日報 / 技術週刊 / 粉絲專頁 / 訂閱RSS

留言討論