日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > c/c++ >内容正文

c/c++

C/C++开发中防止头文件被重复引入的3种方法

發布時間:2025/3/12 c/c++ 19 豆豆
生活随笔 收集整理的這篇文章主要介紹了 C/C++开发中防止头文件被重复引入的3种方法 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

?

? ?我們在用 C 語言開發軟件時,經常使用宏定義(#ifndef / #define / #endif)來有效避免頭文件被重復 #include,此方式在 C++ 多文件編程中也很常用。
? ?舉個例子,如下是一個 C++ 項目,其內部含有 school.h 和 student.h 這 2 個頭文件以及 main.cpp 源文件,其各自包含的代碼為:

//student.h class Student {//...... };//school.h #include "student.h" class School {//...... private:Student stu[50]; };//main.cpp #include "student.h" #include "school.h" int main() {//......return 0; }

? 運行此項目讀者會發現,編譯器報“Student 類型重定義”錯誤。這是因為在 school.h 文件中已經 #include 了一次 "student.h",而在 main.cpp 主程序又同時 #include 了 "school.h" 和 "student.h",即 Student 類的定義被引入了 2 次,C++不允許同一個類被重復定義。
有讀者可能想到,既然 School.h 文件中已經引入了 Student 類,那去掉 main.cpp 主程序引入的 student.h 文件不就可以了嗎?這樣確實可以避免重復引入 Student 類,但此方式并不適用于所有“重復引入”的場景。
C++ 多文件編程中,處理“多次 #include 導致重復引入”問題的方式有以下 3 種。

1) 使用宏定義避免重復引入

在實際多文件開發中,我們往往使用如下的宏定義來避免發生重復引入:

#ifndef _NAME_H #define _NAME_H //頭文件內容 #endif

?其中,_NAME_H 是宏的名稱。需要注意的是,這里設置的宏名必須是獨一無二的,不要和項目中其他宏的名稱相同。

當程序中第一次 #include 該文件時,由于 _NAME_H 尚未定義,所以會定義 _NAME_H 并執行“頭文件內容”部分的代碼;當發生多次 #include 時,因為前面已經定義了 _NAME_H,所以不會再重復執行“頭文件內容”部分的代碼。

也就是說,我們可以將前面項目中的 student.h 文件做如下修改:

#ifndef _STUDENT_H #define _STUDENT_H class Student {//...... }; #endif

?雖然該項目 main.cpp 文件中仍 #include 了 2 次 "student.h",但鑒于 _STUDENT_H 宏只能定義一次,所以 Student 類也僅會定義一次。再次執行該項目會發現,其可以正常執行。

? ? 優點:

  • 受C/C++語言標準的支持,不受編譯器的限制。
  • 不僅僅局限于避免同一個文件被重復包含,也能避免內容完全相同的兩個文件(或代碼片段)被重復包含。
  • ? ? 缺點:

  • 如果不同頭文件中的宏名恰好相同,可能就會導致你看到頭文件明明存在,編譯器卻說找不到聲明的情況。
  • 由于編譯器每次都需要打開頭文件才能判定是否有重復定義,因此在編譯大型項目時,#ifndef會使得編譯時間相對較長。
  • 2) 使用#pragma once避免重復引入

    除了前面第一種最常用的方式之外,還可以使用 #pragma one 指令,將其附加到指定文件的最開頭位置,則該文件就只會被 #include 一次。

    我們知道,#ifndef 是通過定義獨一無二的宏來避免重復引入的,這意味著每次引入頭文件都要進行識別,所以效率不高。但考慮到 C 和 C++ 都支持宏定義,所以項目中使用 #ifndef 規避可能出現的“頭文件重復引入”問題,不會影響項目的可移植性。

    和 ifndef 相比,#pragma once 不涉及宏定義,當編譯器遇到它時就會立刻知道當前文件只引入一次,所以效率很高。但值得一提的是,并不是每個版本的編譯器都能識別 #pragma once 指令,一些較老版本的編譯器就不支持該指令(執行時會發出警告,但編譯會繼續進行),即 #pragma once 指令的兼容性不是很好。

    目前,幾乎所有常見的編譯器都支持 #pragma once 指令,甚至于 Visual Studio 2017 新建頭文件時就會自帶該指令。可以這么說,在 C/C++ 中,#pragma once 是一個非標準但卻逐漸被很多編譯器支持的指令。

    除此之外,#pragma once 只能作用于某個具體的文件,而無法向 #ifndef 那樣僅作用于指定的一段代碼。
    這里仍以前面的 "student.h" 文件為例,將其內容修改為:

    #pragma once class Student {//...... };

    ?再次運行項目,同樣可以正常執行。

    ? ?優點:

  • 避免#ifndef中因為宏名相同導致的問題。
  • 由于編譯器不需要打開頭文件就能判定是否有重復定義,因此在編譯大型項目時,比#ifndef更快。
  • ? ?缺點:

  • #pragma once只針對同一文件有效,對相同的兩個文件(或代碼片段)使用無效。
  • #pragma once不受一些較老版本的編譯器支持,一些支持了的編譯器又打算去掉它,所以它的兼容性可能不夠好。
  • 3) 使用_Pragma操作符

    C99 標準中新增加了一個和 #pragma 指令類似的 _Pragma 操作符,其可以看做是 #pragma 的增強版,不僅可以實現 #pragma 所有的功能,更重要的是,_Pragma 還能和宏搭配使用。

    有關 _Pragma 操作符更多的功能和用法,本節不做詳細講解,這里僅介紹如何用 _Pragma 操作符避免頭文件重復引入。

    當處理頭文件重復引入問題時,可以將如下語句添加到相應文件的開頭:

    _Pragma("once")

    比如,將該語句添加到前面項目中 student.h 文件中的開頭位置,再次執行項目,其可以正常執行。

    事實上,無論是 C 語言還是 C++,為防止用戶重復引入系統庫文件,幾乎所有庫文件中都采用了以上 3 種結構中的一種,這也是為什么重復引入系統庫文件編譯器也不會報錯的原因。

    ?總結

    本節介紹了 3 種避免頭文件被重復引入的方法,其中 #pragma once 和 _Pragma("once") 可算作一類,其特點是編譯效率高,但可移植性差(編譯器不支持,會發出警告,但不會中斷程序的執行);而 #ifndef 的特點是可移植性高,編譯效率差。讀者可根據實際情況,挑選最符合實際需要的解決方案。

    除非對項目的編譯效率有嚴格的要求,強烈推薦讀者選用第一種解決方案,即采用 #ifndef / #define / #endif 組合解決頭文件被重復引入。

    另外在某些場景中,考慮到編譯效率和可移植性,#pragma once 和 #ifndef 經常被結合使用來避免頭文件被重復引入。比如說:

    #pragma once #ifndef _STUDENT_H #define _STUDENT_H class Student {//...... }; #endif

    ?當編譯器可以識別 #pragma once 時,則整個文件僅被編譯一次;反之,即便編譯器不識別 #pragma once 指令,此時仍有 #ifndef 在發揮作用。

    混合使用需要注意的是:
    1.只要使用了#ifndef就會有宏名沖突的危險。
    2.混合使用無法避免不支持#pragma once的編譯器報錯。
    所以混合使用并不一定能得到很好的效果,具體怎么使用,需要視情況而定。

    ?

    總結

    以上是生活随笔為你收集整理的C/C++开发中防止头文件被重复引入的3种方法的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。