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

我正在通过Implementation defined behavior control

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

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

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

TIA

【问题讨论】:

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

标签: c++ pragma include-guards


【解决方案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 作为包含保护。

  1. 您使用的库中的头文件可能已经定义了它。
  2. 由于复制和粘贴错误,您可以在自己的代码库中使用 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 文件根据文件系统级身份被排除在外,因此如果出现以下情况,这不能防止包含两次标头它存在于一个项目中的多个位置。”
猜你喜欢
  • 1970-01-01
  • 2017-09-15
  • 1970-01-01
  • 2011-02-27
  • 2016-09-17
  • 2010-11-11
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多