#pragma once 是一种预处理器指令,在 C++ 中用于告诉编译器该文件只应被包含一次。当在一个项目中某个头文件可能会被其他源文件多次包含时,为了防止宏定义重复导致的问题(比如循环依赖或名称冲突),程序员会使用#pragma once 替代标准的 #ifndef ... #define ... #endif 结构。
当编译器遇到#pragma once,它会在第一次遇到该指令时立即包含文件的内容,并将这个标记存储起来。如果之后再尝试第二次包含,编译器会跳过已包含的内容,避免了不必要的重复。然而,#pragma once 并不是所有编译器都支持的标准特性,一些老旧的或非Microsoft的编译器可能不识别。在这种情况下,还是需要使用传统的条件编译指令。是许多现代的编译器如Microsoft Visual C++、GCC(GNU Compiler Collection)、Clang 等广泛采用的一种非正式约定。
#pragma once 和 include guards(通常使用`#ifndef ... #define ... #endif`的形式)都是用于防止头文件内容被重复包含的技术。它们的区别在于:
1. 标准支持:
- `#ifndef ... #define ... #endif`是C/C++的传统做法,是编译器无关的标准解决方案,适用于所有支持预处理器的编译器,包括那些未直接支持#pragma once的。
2. 编译器依赖:
- `#pragma once`是非标准的,但它在许多现代编译器(如MSVC、GCC、Clang等)中有很好的支持,如果编译器不支持,可能会忽略该指令,所以最好还是配合`#ifndef`来编写。
3. 效率:
- include guards的工作原理是检查宏是否已经定义过,如果未定义则进行包含并设置宏;下一次包含时,由于宏已存在,就不会再次包含内容。这可能导致额外的条件检查开销。
- pragmas like `#pragma once`更高效,因为它们是编译器级别的机制,可以在编译阶段立即阻止重复包含,避免了每次包含时的检查过程。
4. 移植性:
- include guards对于所有支持预处理器的编译器都是可用的,而#pragma once的适用性取决于具体的编译环境。
综上,尽管`#ifndef`+`#define`更为通用,但在实际开发中,如果你对所使用的编译器有较高的信任度,#pragma once 可能会提供更好的性能。