#pragma 一次与包括警卫

#pragma once vs. include guards

本文关键字:包括警 一次 #pragma      更新时间:2023-10-16

我正在通过实现定义的行为控制

关于#pragma once有以下文字:

与标头保护不同,此编译指示使得不可能在多个文件中错误地使用相同的宏名称。

我不确定这意味着什么。有人可以解释一下吗?

蒂亚

示例:

// src/featureA/thingy.h
#ifndef HEADER_GUARD_FOR_THINGY
#define HEADER_GUARD_FOR_THINGY
struct foo{};
#endif

// src/featureB/thingy.h
#ifndef HEADER_GUARD_FOR_THINGY
#define HEADER_GUARD_FOR_THINGY
struct bar{};
#endif

// src/file.cpp
#include "featureA/thingy.h"
#include "featureB/thingy.h" // oops, this file is removed by header guard
foo f;
bar b;

标头保护宏需要一丝不苟的努力才能保持其唯一性。#pragma once会自动执行此操作。

为了公平和完整起见,让我提到缺点(也在链接页面中):如果从多个路径包含同一个文件,#pragma once则无法识别该文件。对于具有奇异文件结构的项目来说,这可能是一个问题。例:

// /usr/include/lib.h
#pragma once
struct foo{};

// src/ext/lib.h
#pragma once
struct foo{};

// src/headerA.h
#pragma once
#include <lib.h>
// src/headerB.h
#pragma once
#include "ext/lib.h"
// src/file.cpp
#include "headerA.h"
#include "headerB.h" // oops, lib.h is include twice
foo f;

假设你有一个头文件 File1.h。您使用以下命令创建了 File1.h:

#ifndef FILE_1_H
#define FILE_1_H
// Contents of File1.h
#endif

该语言中没有任何内容可以阻止其他头文件使用相同的宏,FILE_1_H,就像包含保护一样。

  1. 您使用的库中的头文件可能已经定义了这一点。
  2. 由于复制和粘贴错误,您可以在自己的代码库中的 File2.h 中使用相同的标头保护。

发生这种情况时,.cpp文件中只能#include一个 .h 文件。在最好的情况下,您将收到编译器错误,这些错误将允许解决问题。在最坏的情况下,您最终将使用错误的类型或函数,并且问题将在运行时表现出来。

由于这些原因,包含防护装置不坚固,容易出现用户错误。

但是,如果您的编译器支持它并且您使用

#pragma once

在所有头文件中,将避免此类错误。


请注意,使用

#pragma once 

有其自身的缺点。有关此内容的更多信息,请参阅以下内容:

#pragma 曾经是保险箱吗?
使用一次 #pragma 有什么危险?

包括守卫看起来像这样:

#ifndef SOME_NAME
#define SOME_NAME
// The header file contents
#endif

虽然有命名约定,但没有什么可以强制宏(在本例中为SOME_NAME)实际调用什么。如果尝试包含两个使用相同宏名称的头文件,编译器将看不到第二个文件的内容,因为该文件的#ifndef ___将失败(宏已在第一个文件中定义)。

#pragma once不存在此问题。