#ifndef 與 #program once 的區別

NO IMAGE

(轉)#ifndef 與 #program once 的區別  

2011-09-12 11:58:50|  分類: vc 編譯執行錯誤|字號 訂閱

來自:http://blog.csdn.net/hkx1n/article/details/4313357

為了避免同一個檔案被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宣告,而只能針對檔案。
    其好處是,你不必再費勁想個巨集名了,當然也就不會出現巨集名碰撞引發的奇怪問題。大型專案的編譯速度也因此提高了一些。
    對應的缺點就是如果某個標頭檔案有多份拷貝,本方法不能保證他們不被重複包含。當然,相比巨集名碰撞引發的“找不到宣告”的問題,這種重複包含很容易被發現並修正。

    #pragma once方式產生於#ifndef之後,因此很多人可能甚至沒有聽說過。目前看來#ifndef更受到推崇。因為#ifndef受C/C 語言標準的支援,不受編譯器的任何限制;而#pragma once方式卻不受一些較老版本的編譯器支援,一些支援了的編譯器又打算去掉它,所以它的相容性可能不夠好。一般而言,當程式設計師聽到這樣的話,都會選擇#ifndef方式,為了努力使得自己的程式碼“存活”時間更久,通常寧願降低一些編譯效能,這是程式設計師的個性,當然這是題外話啦。

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

    #pragma once
    #ifndef __SOMEFILE_H__
    #define __SOMEFILE_H__
    … … // 宣告、定義語句
    #endif

    看起來似乎是想兼有兩者的優點。不過只要使用了#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方式的支援,這一特性應該基本穩定下來了。