#pragma 一次与包括守卫 [重复]

#pragma once vs. include guards [duplicate]

提问人:Vinod 提问时间:2/23/2019 更新时间:2/23/2019 访问量:6872

问:

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

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

与标头防护不同,此杂注使得不可能在多个文件中错误地使用相同的宏名称。

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

短暂性投资安全

C++ 编译指示 include-guards

评论

0赞 Slava 2/23/2019
这意味着您可以错误地在不同文件中使用相同的宏作为守卫
2赞 user4581301 2/23/2019
请注意,它有一些缺陷,这些缺陷可能会被中等复杂的项目结构所暴露。#pragma once
0赞 Pete Becker 2/23/2019
@user4581301——确实如此。这就是为什么它不是标准 C 或标准 C++ 的一部分。#pragma once
0赞 pooya13 2/23/2019
你可能想看看这个问题:stackoverflow.com/questions/1143936/......

答:

10赞 eerorika 2/23/2019 #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;

评论

1赞 Pete Becker 2/23/2019
虽然这一切都是正确的,但它没有提到包括防护装置不存在的问题。#pragma once
0赞 eerorika 2/23/2019
@PeteBecker这不是我们想要的。但无论如何,我现在为了完整起见而添加了它。
2赞 R Sahu 2/23/2019 #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 文件。在最好的情况下,您将收到编译器错误,从而可以解决问题。在最坏的情况下,您最终会使用错误的类型或函数,并且问题将在运行时表现出来。#include

由于这些原因,包含防护不可靠,并且容易受到用户错误的影响。

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

#pragma once

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


请注意,使用

#pragma once 

有其自身的一系列缺点。有关详细信息,请参阅以下内容:

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

评论

0赞 Pete Becker 2/23/2019
虽然这一切都是正确的,但它没有提到包括防护装置不存在的问题。#pragma once
0赞 R Sahu 2/23/2019
@PeteBecker,没错。然而,它与OP的问题是正交的。
1赞 Kevin 2/23/2019 #3

包括防护如下所示:

#ifndef SOME_NAME
#define SOME_NAME

// The header file contents

#endif

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

此问题不存在。#pragma once

评论

0赞 Pete Becker 2/23/2019
虽然这一切都是正确的,但它没有提到包括防护装置不存在的问题。#pragma once
0赞 Kevin 2/23/2019
@PeteBecker 我在 OP 中回答了这个问题,这是对报价的解释。
0赞 Pete Becker 2/23/2019
是的,但你没有提到这句话具有误导性。
0赞 Kevin 2/23/2019
@PeteBecker 我看不出它是如何误导的。它解释了头卫士的缺点,而头卫士没有。引文的下一句话解释了以下的缺点:“另一方面,由于 #pragma 一次文件会根据其文件系统级标识被排除,因此如果标头存在于项目中的多个位置,则无法防止包含两次标头。#pragma once#pragma once