#pragma once vs. include guards [重复]

Posted

技术标签:

【中文标题】#pragma once vs. include guards [重复]【英文标题】:#pragma once vs. include guards [duplicate] 【发布时间】:2019-02-23 03:32:23 【问题描述】:

我正在通过Implementation defined behavior control

还有与#pragma once相关的以下文字:

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

我不确定这意味着什么。谁能解释一下?

TIA

【问题讨论】:

这意味着您可以在不同的文件中使用相同的宏作为保护错误 请注意,#pragma once 存在缺陷,可以通过适度复杂的项目结构暴露出来。 @user4581301 — 确实如此。这就是为什么#pragma once 不是标准 C 或标准 C++ 的一部分。 你可能想看看这个问题:***.com/questions/1143936/… 【参考方案1】:

例子:

// 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;

【讨论】:

虽然这一切都是正确的,但它并没有提到 #pragma once 所具有的包含保护不存在的问题。 @PeteBecker 这不是我们想要的。但我现在添加它是为了完整性。【参考方案2】:

假设您有一个头文件 File1.h。您创建了 File1.h:

#ifndef FILE_1_H
#define FILE_1_H

// Contents of File1.h

#endif

语言中没有任何内容可以阻止其他头文件使用相同的宏 FILE_1_H 作为包含保护。

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

发生这种情况时,.cpp 文件中只有一个 .h 文件可以是 #included。在最好的情况下,您会得到可以解决问题的编译器错误。在最坏的情况下,您最终会使用错误的类型或函数,并且问题会在运行时显现出来。

由于这些原因,包含守卫并不健壮并且容易受到用户错误的影响。

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

#pragma once

在你所有的头文件中,这样的错误都会被避免。


请注意使用

#pragma once 

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

Is #pragma once a safe include guard?What are the dangers of using #pragma once?

【讨论】:

虽然这一切都是正确的,但它并没有提到 #pragma once 所具有的包含保护不存在的问题。 @PeteBecker,真的。然而,它与 OP 的问题是正交的。【参考方案3】:

包括警卫看起来像这样:

#ifndef SOME_NAME
#define SOME_NAME

// The header file contents

#endif

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

#pragma once 不存在此问题。

【讨论】:

虽然这一切都是正确的,但它并没有提到 #pragma once 所具有的包含保护不存在的问题。 @PeteBecker 我正在回答 OP 中的问题,这是对报价的解释。 是的,但你没有提到这句话具有误导性。 @PeteBecker 我看不出它有什么误导性。它解释了 #pragma once 没有的头部防护的缺点。引文的下一句解释了#pragma once 的缺点:“另一方面,由于#pragma once 文件根据文件系统级身份被排除在外,因此如果出现以下情况,这不能防止包含两次标头它存在于一个项目中的多个位置。”

以上是关于#pragma once vs. include guards [重复]的主要内容,如果未能解决你的问题,请参考以下文章

#pragma once 与 #ifdef 的区别

C++中防止多次包含头文件:#pragma once和 #indef的区别

C++中防止多次包含头文件:#pragma once和 #indef的区别

C++中防止多次包含头文件:#pragma once和 #indef的区别

#pragma once与 #ifndef的区别

#pragma once与#ifndef的区别