天天看點

關于C++/C中防止頭檔案的重複包含的解決辦法

為了避免同一個檔案被include多次,C/C++中有兩種方式,一種是#ifndef方式,一種是#pragma

once方式。在能夠支援這兩種方式的編譯器上,二者并沒有太大的差別,但是兩者仍然還是有一些細微的差別。

方式一:

#ifndef __SOMEFILE_H__

#define __SOMEFILE_H__

... ... // 聲明、定義語句

#endif

方式二:

#pragma once

#ifndef的方式受C/C++語言标準支援。它不光可以保證同一個檔案不會被包含多次,也能保證内容完全相同的兩個檔案(或者代碼片段)不會被不小心同時包含。

當然,缺點就是如果不同頭檔案中的宏名不小心“撞車”,可能就會導緻你看到頭檔案明明存在,編譯器卻硬說找不到聲明的狀況——這種情況有時非常讓人抓狂。

由于編譯器每次都需要打開頭檔案才能判定是否有重複定義,是以在編譯大型項目時,ifndef會使得編譯時間相對較長,是以一些編譯器逐漸開始支援#pragma

once的方式。

#pragma

once一般由編譯器提供保證:同一個檔案不會被包含多次。注意這裡所說的“同一個檔案”是指實體上的一個檔案,而不是指内容相同的兩個檔案。你無法對一個頭檔案中的一段代碼作pragma

once聲明,而隻能針對檔案。

其好處是,你不必再費勁想個宏名了,當然也就不會出現宏名碰撞引發的奇怪問題。大型項目的編譯速度也是以提高了一些。

對應的缺點就是如果某個頭檔案有多份拷貝,本方法不能保證他們不被重複包含。當然,相比宏名碰撞引發的“找不到聲明”的問題,這種重複包含很容易被發現并修正。

once方式産生于#ifndef之後,是以很多人可能甚至沒有聽說過。目前看來#ifndef更受到推崇。因為#ifndef受C/C++語言标準的支援,不受編譯器的任何限制;而#pragma

once方式卻不受一些較老版本的編譯器支援,一些支援了的編譯器又打算去掉它,是以它的相容性可能不夠好。一般而言,當程式員聽到這樣的話,都會選擇#ifndef方式,為了努力使得自己的代碼“存活”時間更久,通常甯願降低一些編譯性能,這是程式員的個性,當然這是題外話啦。

還看到一種用法是把兩者放在一起的:

看起來似乎是想兼有兩者的優點。不過隻要使用了#ifndef就會有宏名沖突的危險,也無法避免不支援#pragma

once的編譯器報錯,是以混用兩種方法似乎不能帶來更多的好處,倒是會讓一些不熟悉的人感到困惑。

選擇哪種方式,應該在了解兩種方式的情況下,視具體情況而定。隻要有一個合理的約定來避開缺點,我認為哪種方式都是可以接受的。而這個已經不是标準或者編譯器的責任了,應當由程式員自己或者小範圍内的開發規範來搞定。

btw:我看到GNU的一些讨論似乎是打算在GCC

3.4(及其以後?)的版本取消對#pragma once的支援。不過事實上,我手上的GCC 3.4.2和GCC 4.1.1仍然支援#pragma

once,甚至沒有deprecation warning,倒是GCC2.95會對#pragma

once提出warning。

VC6及其以後版本亦提供對#pragma

once方式的支援,這一特性應該基本穩定下來了。

繼續閱讀