11

#pragma once将包含防护装置放置在内部与外部放置之间有什么区别吗?

情况1:

#ifndef SOME_HEADER_H
#define SOME_HEADER_H
#pragma once

案例2:

#pragma once
#ifndef SOME_HEADER_H
#define SOME_HEADER_H

我只是出于好奇想知道是否有任何特殊情况我应该更喜欢其中一种(案例 1 或案例 2),因为我决定在我的代码中结合两者(编译指示和标头保护)。

编辑:

我认为你们误解了我的问题......我问的是 的位置pragma once,而不是 pragma once -vs- header guards。

4

3 回答 3

7

有一个细微的区别,如果SOME_HEADER_H在包含标头之前已经定义了,那么在第二种情况下,预处理器将处理#pragma once,而在第一种情况下则不会。

如果您#undef SOME_HEADER_H再次通过同一个 TU 包含该文件,您将看到功能差异:

#define SOME_HEADER_H
#include "some_header.h"
#undef SOME_HEADER_H
#include "some_header.h"

现在,在案例 1 中,我拥有头文件中的所有定义。在情况2我没有。

即使没有#undef,由于在案例 1 中被忽略,您也可以想象到预处理时间的差异#pragma once。这取决于实现。

我可以想到在第一次包含此头文件之前已经定义的两种可能的方式:

  • (显而易见的)一个完全独立的文件定义了它,无论是故意的还是偶然的名称冲突,
  • 该文件的副本已经定义了它。取决于可能包括此文件在两个不同文件名下涉及同一 TU 的情况的实现,例如由于符号链接或文件系统合并。如果您的实现支持#pragma once,并且您非常仔细地检查了它的文档,您可能能够找到一个明确的声明,是通过包含文件的路径应用优化,还是通过比较识别文件存储的东西,如 inode数字。如果是后者,您甚至可以弄清楚是否仍然存在可以欺骗预处理器的骗局,例如远程安装本地文件系统以隐藏它“确实是同一个文件”......

#pragma once但是,以预期的方式使用,只要实现以 Microsoft 定义的方式处理,就没有区别。只要它被处理而不是被跳过,它就会标记包含文件以进行优化,因此它是否会在第二遍文件中被处理并不重要——第二遍不会发生。

当然,由于 pragma 是非标准的,至少在理论上,它在不同的实现上可能具有完全不同的含义,在这种情况下,它何时以及处理多少次可能很重要。在实践中,你会认为没有人会这样做。

于 2011-03-21T22:23:28.623 回答
6

它们是多余的。

#pragma once并非所有编译器都支持,而包含警卫则支持。只需使用包括警卫。像 gcc 这样的编译器足够聪明,可以理解包含守卫,甚至不会再次打开文件。

于 2011-03-21T19:17:02.513 回答
1

要回答您的问题:

情况1:

编译器将检查是否设置了预处理器常量,如果没有定义它,然后检查#pragma ońce 指令。这很可能是对字符串“SOME_HEADER_H”的哈希查找,以了解它是否已定义,然后再对当前文件名进行另一次哈希查找(可能是预处理器设置的 __ FILE __ 常量)。因此,如果该文件从未被读取,我们将进行两次哈希查找和两次哈希保存,如果该文件已被读取,则只需一次哈希查找。

案例二:

这显然与案例 1 相同,但顺序相反。所以我们唯一可以比较的是用作查找的哈希键的长度。根据当前头文件的路径,即路径的长度,#pragma once 指令的哈希查找可能计算起来更昂贵。如果文件名是“C:\dude.h”,它比“SOME_HEADER_H”短。

所以我想总结一下。不,没有特殊情况,案例 1 会比案例 2 更有益,反之亦然。至少不要对 Heureka 大喊大叫 ;)

干杯

于 2011-03-21T21:32:02.607 回答