内部和外部的pragma之间的区别包括守卫?

时间:2011-03-21 19:08:43

标签: c++ c include-guards

#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和header guard)结合起来。 / p>

修改

我认为你们错误解释了我的问题......我问的是pragma once的位置,而不是pragma一次-vs-标题后卫。

3 个答案:

答案 0 :(得分:6)

如果在包含标题之前已经定义了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编号。如果是后者,你甚至可以弄清楚是否仍然存在可以被欺骗以欺骗预处理器的诈骗,例如远程安装本地文件系统以隐藏它是“真正的同一个文件”......

以预期的方式使用,如果实现以Microsoft定义它的方式处理#pragma once,则没有区别。只要它被处理而不是跳过,它就会标记优化的包含文件,因此无论是否在第二次通过文件时处理它都无关紧要 - 第二遍不会发生。

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

答案 1 :(得分:5)

他们是多余的。

所有编译器都不支持

#pragma once,而包括警卫。只需使用包含警卫。像gcc这样的编译器非常聪明,可以理解包含警卫,甚至不再打开文件。

答案 2 :(得分:1)

回答你的问题:

案例1:

编译器将检查预处理器常量是否已设置,如果未定义,则检查#pragmaońce指令。这很可能是对字符串“SOME_HEADER_H”进行哈希查找,以便在对当前文件名(可能是预处理器设置的__ FILE __常量)执行另一个哈希查找之前知道它是否已定义。因此,如果文件从未被读过,我们有两个哈希查找和两个哈希保存,如果文件只读取了一个哈希查找。

案例2:

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

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

干杯