面试题答案
一键面试功能差异
- #pragma once:
- 功能上确保头文件在一个编译单元中只被包含一次。它由编译器识别,编译器在处理到该指令时,会记录已经遇到的头文件,后续再次遇到相同头文件的包含指令时,不再重复处理。
- 不需要额外定义宏,简洁明了,且对整个头文件起作用。
- #include guard:
- 通过定义唯一的宏来防止头文件重复包含。在头文件开始处定义一个宏,在文件结尾取消定义。每次包含头文件时,先检查宏是否已定义,若已定义则跳过文件内容,否则处理文件内容并定义宏。
- 依赖用户定义的宏,若宏定义不唯一,可能导致头文件重复包含问题。
性能差异
- #pragma once:
- 编译器实现机制相对高效,因为编译器内部维护一个已包含头文件的列表,遇到已在列表中的头文件包含指令直接跳过,无需进行宏定义的检查等额外操作。
- #include guard:
- 每次包含头文件时都需要检查宏是否已定义,虽然现代编译器对宏处理有优化,但相比之下,多了宏定义和检查的开销。
适用场景差异
- #pragma once:
- 适用场景:适用于大多数现代编译器支持的项目场景,尤其是在同一个项目组内开发,且编译器都支持该指令的情况下。例如在iOS开发项目中,Xcode使用的Clang编译器支持
#pragma once
,项目内新编写的头文件可以广泛使用。 - 不适用场景:当项目需要跨平台支持一些不支持
#pragma once
的古老编译器时,可能不适用。
- 适用场景:适用于大多数现代编译器支持的项目场景,尤其是在同一个项目组内开发,且编译器都支持该指令的情况下。例如在iOS开发项目中,Xcode使用的Clang编译器支持
- #include guard:
- 适用场景:具有更好的跨平台兼容性,几乎所有C和Objective - C编译器都支持宏定义,所以在需要跨多种编译器甚至跨语言(如C和C++混合项目且存在头文件共享)的项目中更适用。比如一些开源库,为了保证广泛的兼容性,多采用
#include guard
。 - 不适用场景:在不需要跨平台,且只使用现代编译器的项目中,相比
#pragma once
显得较为繁琐。
- 适用场景:具有更好的跨平台兼容性,几乎所有C和Objective - C编译器都支持宏定义,所以在需要跨多种编译器甚至跨语言(如C和C++混合项目且存在头文件共享)的项目中更适用。比如一些开源库,为了保证广泛的兼容性,多采用
何时更适合使用#pragma once举例
假设正在开发一个iOS应用的内部框架,团队使用的都是Xcode开发环境(Clang编译器),这种情况下使用#pragma once
更合适。例如有一个MyFrameworkHeader.h
头文件:
// MyFrameworkHeader.h
#pragma once
#import <UIKit/UIKit.h>
@interface MyClass : NSObject
- (void)doSomething;
@end
这样可以简洁高效地防止该头文件在编译单元中重复包含,而且不需要担心宏定义冲突等问题。