【C/C++】不同防止頭文件重復包含的措施

文章目錄

  • #pragma once vs #ifndef 文件宏
    • 1 原理層面區別(core)
    • 2 關鍵區別與優缺點分析
    • 3 總結與最佳實踐

#pragma once vs #ifndef 文件宏

在 C/C++ 中,#pragma once 和傳統的文件宏守衛 (#ifndef HEADER_H #define HEADER_H ... #endif) 都用于防止頭文件在單個翻譯單元(通常是一個 .cpp 文件及其遞歸包含的所有頭文件)中被重復包含多次。

1 原理層面區別(core)

  1. #pragma once (編譯器指令):

    • 底層處理: 這是一個編譯器特定的指令(盡管幾乎所有現代編譯器都支持它)。當編譯器遇到 #pragma once 時:
      • 它會在其內部維護一個數據結構(通常是一個集合或哈希表),記錄已經包含過哪些物理文件。
      • 這個記錄通常基于文件的唯一標識符,在大多數系統上是文件的絕對路徑(inode 或其他底層文件系統標識符也可能參與)。
      • 當編譯器再次遇到包含同一個物理文件的 #include 指令時(基于這個唯一標識符判斷),它會直接跳過包含該文件的整個內容。
    • 本質: 編譯器基于文件的物理身份(路徑/inode)來防止重復包含。它不需要查看或修改頭文件的內容本身。
  2. 文件宏守衛 (#ifndef HEADER_H / #define HEADER_H / #endif) (預處理器機制):

    • 底層處理: 這是一個預處理器機制,發生在編譯器進行真正的詞法分析、語法分析之前。
      • 當預處理器處理頭文件時,第一次遇到 #ifndef HEADER_H 時,因為 HEADER_H 尚未定義,條件為真。
      • 接著它執行 #define HEADER_H,將這個宏名放入預處理器維護的符號表中。
      • 然后處理頭文件內容直到 #endif
      • 如果同一個翻譯單元中再次嘗試包含該頭文件,預處理器再次遇到 #ifndef HEADER_H。此時 HEADER_H 已在符號表中定義,因此條件為假。預處理器會跳過從 #ifndef 到匹配的 #endif 之間的所有內容。
    • 本質: 預處理器基于一個在頭文件內容中手動定義的、唯一的宏名稱(HEADER_H)來防止重復包含。它依賴于文本替換和宏定義狀態。

2 關鍵區別與優缺點分析

特性#pragma once文件宏守衛 (#ifndef HEADER_H)
標準合規性非標準 (但被所有主流編譯器廣泛支持:MSVC, GCC, Clang, ICC)標準 C/C++ (由語言標準保證)
底層機制編譯器 基于物理文件標識符 (路徑/inode)預處理器 基于宏名稱在符號表中的存在性
唯一性要求由文件系統路徑/標識符保證(通常可靠)由程序員手動確保宏名稱全局唯一 (易出錯,如復制粘貼頭文件導致沖突)
處理速度通常更快:編譯器只需檢查文件ID集合。首次包含后,后續包含幾乎立即跳過。可能稍慢:預處理器每次都需要打開文件(或緩存內容),查找宏定義狀態。即使跳過內容,也可能需要詞法掃描到 #endif
符號鏈接/硬鏈接行為取決于編譯器實現:大多數編譯器基于最終物理文件(inode),因此符號鏈接通常能正確處理。不同路徑指向同一物理文件也能正確處理。基于包含指令的路徑:如果通過不同路徑(符號鏈接或直接路徑)包含同一個物理文件,預處理器看到的是不同的宏定義指令(不同文件名),導致重復包含。
文件內容依賴無依賴:即使頭文件內容為空或無效,只要指令存在就有效。強依賴:宏定義必須正確、唯一地寫在文件開頭和結尾。
拷貝文件問題拷貝頭文件:視為不同物理文件,會被包含多次。拷貝頭文件:如果宏名不同,會被包含多次;如果宏名相同,后續拷貝被跳過(但這是錯誤,拷貝文件應有獨立宏名)。
跨平臺/編譯器依賴編譯器支持(雖然現在支持極廣),理論上不如宏守衛可移植。標準機制,可移植性最高。
錯誤處理重復包含通常被靜默跳過。宏名沖突會導致意外的跳過或包含。

3 總結與最佳實踐

  1. #pragma once 的優勢:
    • 簡潔: 一行代碼搞定。
    • 不易出錯: 無需發明唯一宏名,避免命名沖突。
    • 通常更快: 編譯器優化更直接。
    • 處理鏈接文件更可靠: 對同一物理文件的不同路徑包含更安全。
  2. 文件宏守衛的優勢:
    • 標準合規: 100% 符合 C/C++ 標準。
    • 最大可移植性: 適用于任何符合標準的編譯器(包括非常古老的或嵌入式編譯器)。
    • 對文件副本更明確: 物理副本需要不同的宏名(這是應該的),行為更直觀(雖然宏名沖突是問題)。
  3. 最佳實踐 (現代 C/C++ 開發):
    • 優先使用 #pragma once: 對于絕大多數現代項目(使用 GCC >= 3.4, Clang, MSVC, ICC 等),#pragma once 是推薦的首選方式。它的簡潔性、性能和避免宏名沖突的優勢顯著。
    • 如果需要最大可移植性或目標編譯器未知: 使用文件宏守衛。
    • 混合使用 (常見且安全): 很多項目/IDE 生成的代碼同時使用兩者:
      #pragma once
      #ifndef MYPROJECT_UTILS_H
      #define MYPROJECT_UTILS_H
      // ... 頭文件內容 ...
      #endif // MYPROJECT_UTILS_H
      
      • #pragma once 提供主要保護和性能。
      • 文件宏守衛提供后備機制,萬一編譯器不支持 #pragma once(極罕見)或遇到符號鏈接路徑處理不一致(理論情況),也能保證正確性。同時也清晰標明了文件結束位置。

底層處理的本質區別一句話概括:#pragma once 是編譯器問“這個物理文件我見過嗎?”,文件宏守衛是預處理器問“這個特定的宏名字我定義過嗎?”。 現代開發中,#pragma once 因其簡潔高效已成為事實標準。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/82745.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/82745.shtml
英文地址,請注明出處:http://en.pswp.cn/web/82745.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

java-springboot文件上傳校驗之只允許上傳excel文件,且檢查不能是腳本或者有害文件或可行性文件

四重驗證機制: 文件擴展名檢查(.xlsx/.xls)MIME類型檢查文件魔數驗證(真實文件類型)可執行文件特征檢測 防御措施: 使用try-with-resources確保流關閉限制文件大小防止DoS攻擊使用Apache POI的FileMagic進…

不確定性分析在LEAP能源-環境系統建模中的整合與應用

本內容突出與實例結合,緊密結合國家能源統計制度及《省級溫室氣體排放編制指南》,深入淺出地介紹針對不同級別研究對象時如何根據數據結構、可獲取性、研究目的,構建合適的能源生產、轉換、消費、溫室氣體排放(以碳排放為主&#…

高性能分布式消息隊列系統(四)

八、客戶端模塊的實現 客戶端實現的總體框架 在 RabbitMQ 中,應用層提供消息服務的核心實體是 信道(Channel)。 用戶想要與消息隊列服務器交互時,通常不會直接操作底層的 TCP 連接,而是通過信道來進行各種消息的發布…

QPair 類說明

QPair 類說明 QPair 是一個模板類&#xff0c;用于存儲一對數據項。 頭文件&#xff1a; cpp #include <QPair> qmake 配置&#xff1a; QT core 所有成員列表&#xff08;包括繼承成員&#xff09; 公共類型 類型定義說明first_type第一個元素的類型&#xff…

4.大語言模型預備數學知識

大語言模型預備數學知識 復習一下在大語言模型中用到的矩陣和向量的運算&#xff0c;及概率統計和神經網絡中常用概念。 矩陣的運算 矩陣 矩陣加減法 條件&#xff1a;行數列數相同的矩陣才能做矩陣加減法 數值與矩陣的乘除法 矩陣乘法 條件&#xff1a;矩陣A的列數 矩陣…

uniapp 設置手機不息屏

在使用 UniApp 開發應用時&#xff0c;有時需要在設備長時間未操作時實現息屏保護功能&#xff0c;以節省電量和保護屏幕。以下是如何在 UniApp 中實現這一功能的步驟。 示例一 // 保持屏幕常亮 uni.setKeepScreenOn({keepScreenOn: true });// 監聽應用進入后臺事件 uni.onH…

智能推薦系統:協同過濾與深度學習結合

智能推薦系統&#xff1a;協同過濾與深度學習結合 系統化學習人工智能網站&#xff08;收藏&#xff09;&#xff1a;https://www.captainbed.cn/flu 文章目錄 智能推薦系統&#xff1a;協同過濾與深度學習結合摘要引言技術原理對比1. 協同過濾算法&#xff1a;基于相似性的推…

使用Python和OpenCV實現圖像識別與目標檢測

在計算機視覺領域&#xff0c;圖像識別和目標檢測是兩個非常重要的任務。圖像識別是指識別圖像中的內容&#xff0c;例如判斷一張圖片中是否包含某個特定物體&#xff1b;目標檢測則是在圖像中定位并識別多個物體的位置和類別。OpenCV是一個功能強大的開源計算機視覺庫&#xf…

《基于Apache Flink的流處理》筆記

思維導圖 1-3 章 4-7章 8-11 章 參考資料 源碼&#xff1a; https://github.com/streaming-with-flink 博客 https://flink.apache.org/bloghttps://www.ververica.com/blog 聚會及會議 https://flink-forward.orghttps://www.meetup.com/topics/apache-flink https://n…

LLaMA-Factory 微調 Qwen2-VL 進行人臉情感識別(二)

在上一篇文章中,我們詳細介紹了如何使用LLaMA-Factory框架對Qwen2-VL大模型進行微調,以實現人臉情感識別的功能。本篇文章將聚焦于微調完成后,如何調用這個模型進行人臉情感識別的具體代碼實現,包括詳細的步驟和注釋。 模型調用步驟 環境準備:確保安裝了必要的Python庫。…

Splash動態渲染技術全解析:從基礎到企業級應用(2025最新版)

引言 在Web 3.0時代&#xff0c;87%的網站采用JavaScript動態渲染技術。傳統爬蟲難以應對Ajax加載、SPA應用等場景&#xff0c;Splash作為專業的JavaScript渲染服務&#xff0c;憑借??Lua腳本控制??和??異步處理能力??&#xff0c;已成為動態數據抓取的核心工具。本文…

【應用】Ghost Dance:利用慣性動捕構建虛擬舞伴

Ghost Dance是葡萄牙大學的一個研究項目&#xff0c;研究方向是探索人與人之間的聯系&#xff0c;以及如何通過虛擬舞伴重現這種聯系。項目負責人Cecilia和Rui利用慣性動捕創造出具有流暢動作的虛擬舞伴&#xff0c;讓現實中的舞者也能與之共舞。 挑戰&#xff1a;Ghost Danc…

廣目軟件GM DC Monitor

廣目&#xff08;北京&#xff09;軟件有限公司成立于2024年&#xff0c;技術和研發團隊均來自于一家具有近10年監控系統研發的企業。廣目的技術團隊一共實施了9家政府單位、1家股份制銀行、1家芯片制造企業的數據中心監控預警項目。這11家政企單位由2家正部級、1家副部級、6家…

12-Oracle 23ai Vector 使用ONNX模型生成向量嵌入

一、Oracle 23ai Vector Embeddings 核心概念? 向量嵌入&#xff08;Vector Embeddings&#xff09;?? -- 將非結構化數據&#xff08;文本/圖像&#xff09;轉換為數值向量 - - 捕獲數據的語義含義而非原始內容 - 示例&#xff1a;"數據庫" → [0.24, -0.78, 0.5…

用 NGINX 構建高效 POP3 代理`ngx_mail_pop3_module`

一、模塊定位與作用 協議代理 ngx_mail_pop3_module 讓 NGINX 能夠充當 POP3 代理&#xff1a;客戶端與后端 POP3 服務器之間的所有請求均轉發到 NGINX&#xff0c;由 NGINX 負責與后端會話邏輯。認證方式控制 通過 pop3_auth 指令指定允許客戶端使用的 POP3 認證方法&#xf…

每日算法 -【Swift 算法】三數之和

Swift&#xff5c;三數之和&#xff08;3Sum&#xff09;詳細題解 注釋 拓展&#xff08;LeetCode 15&#xff09; ?題目描述 給你一個包含 n 個整數的數組 nums&#xff0c;判斷 nums 中是否存在三個元素 a, b, c&#xff0c;使得 a b c 0。請你找出所有和為 0 且不重…

服務器磁盤空間被Docker容器日志占滿處理方法

事發場景&#xff1a; 原本正常的服務停止運行了&#xff0c;查看時MQTT服務鏈接失敗&#xff0c;查看對應的容器服務發現是EMQX鏡像停止運行了&#xff0c;重啟也是也報錯無法正常運行&#xff0c;報錯如下圖&#xff1a; 報錯日志中連續出現兩個"no space left on devi…

令牌桶 滑動窗口->限流 分布式信號量->限并發的原理 lua腳本分析介紹

文章目錄 前言限流限制并發的實際理解限流令牌桶代碼實現結果分析令牌桶lua的模擬實現原理總結&#xff1a; 滑動窗口代碼實現結果分析lua腳本原理解析 限并發分布式信號量代碼實現結果分析lua腳本實現原理 雙注解去實現限流 并發結果分析&#xff1a; 實際業務去理解體會統一注…

基于uniapp+WebSocket實現聊天對話、消息監聽、消息推送、聊天室等功能,多端兼容

基于 ?UniApp + WebSocket?實現多端兼容的實時通訊系統,涵蓋WebSocket連接建立、消息收發機制、多端兼容性配置、消息實時監聽等功能,適配?微信小程序、H5、Android、iOS等終端 目錄 技術選型分析WebSocket協議優勢UniApp跨平臺特性WebSocket 基礎實現連接管理消息收發連接…

Linux中shell編程表達式和數組講解

一、表達式 1.1 測試表達式 樣式1: test 條件表達式 樣式2: [ 條件表達式 ] 注意&#xff1a;以上兩種方法的作用完全一樣&#xff0c;后者為常用。但后者需要注意方括號[、]與條件表達式之間至少有一個空格。test跟 [] 的意思一樣條件成立&#xff0c;狀態返回值是0條件不成…