C++ 中的 Pragma Once

Muhammad Husnain 2023年12月11日
C++ 中的 Pragma Once

本文首先概述作為前處理器指令的 pragma once 以及如何使用它的簡單示例。在此之後,我們將介紹 pragma once 關於其在 C 和 C++ 中的支援的一些特定屬性,最後,我們將包含一個更全面的示例,說明如何使用它以及它如何優於其他替代方案。

C++ 中的 Pragma once

pragma once 在 C 和 C++ 中用作前處理器指令。前處理器指令是單行程式碼,不構成程式,而是由前處理器讀取。

前處理器在編譯程式碼之前分析這些。前處理器也不希望在這些指令的末尾有分號。

因此,要將 pragma once 指令新增到你的程式碼中,請將以下內容新增到檔案頂部。

#pragma once

pragma once 本身是非標準的。這意味著一些編譯器將不支援它,並且由於其複雜的實現,它可能並不總是可靠的。

但是,它非常普遍地得到支援;因此在大多數情況下,使用 pragma once 應該不是問題。它的目的很簡單:它確保當前原始檔(正在寫入指令的檔案)在編譯中只包含一次。

這項工作也可以使用 include guards 來完成。我們將在舉例說明如何使用 pragma once 之後討論差異。

pragma once 主要用於定義類時。在下面的例子中,我們將定義兩個類:StructureRoom

Room 類將繼承自 Structure 類。

// This contains the code for the Structure class
// Save this as Structure.h
#pragma once

#include <iostream>
#include <string>

using namespace std;

class Structure {
  string struc_name;
  int id;

 public:
  void setVals() {
    struc_name = "Example Name";
    id = 1;
  }

  void printVals() {
    cout << "Name is: " << struc_name << " and id is: " << id << endl;
  }
};

我們現在將定義 Room 類。

// Save this as Room.h
#pragma once

#include "Structure.h"

class Room {
  Structure example;

 public:
  void initRoom() { example.setVals(); }

  void getRoom() { example.printVals(); }
};

我們現在可以定義一個使用上述物件的 main 函式。

// save this in a main.cpp file
#include <iostream>

#include "Room.h"
#include "Structure.h"

using namespace std;

int main() {
  Room testRoom;

  testRoom.initRoom();
  testRoom.getRoom();

  return 0;
}

在上面的示例中,如果我們執行程式碼,我們會得到 Name is: Example Name and id is: 1 作為輸出,這正是我們所期望的。但是,如果我們刪除 pragma once,我們會收到以下錯誤。

In file included from Room.h:3,
                 from main.cpp:2:
Structure.h:8:7: error: redefinition of 'class Structure'
    8 | class Structure
      |       ^~~~~~~~~
In file included from main.cpp:1:
Structure.h:8:7: note: previous definition of 'class Structure'
    8 | class Structure
      |       ^~~~~~~~~

Structure 類定義了兩次。使用 pragma once,我們可以確保它只被讀取一次。

另一種方法是使用識別符號。在上述示例的上下文中,我們可以按照下面的定義進行操作。

#ifndef STRUCTURE
#define STRUCTURE

class Structure {
  // Some sample code here
};
#endif

在上面的示例中,STRUCTURE 可以替換為任何內容。但是,我們通常將名稱保留為與類名稱相對應的名稱。

但是,這裡可能存在問題。首先,它更冗長,需要手動決策,並且編譯器無法防止程式設計師在專案的其他地方意外使用巨集名稱。

編譯器通常針對 pragma once 進行優化,以提高編譯速度。

Muhammad Husnain avatar Muhammad Husnain avatar

Husnain is a professional Software Engineer and a researcher who loves to learn, build, write, and teach. Having worked various jobs in the IT industry, he especially enjoys finding ways to express complex ideas in simple ways through his content. In his free time, Husnain unwinds by thinking about tech fiction to solve problems around him.

LinkedIn