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