#ifndef 和 #pragma once有什么区别?| 头文件防重复包含详解

#ifndef 和 #pragma once有什么区别? #

前言 #

在C或C++编程中,头文件的重复include是个很常见的问题,很多情况下会导致编译失败。

为了避免这种情况,一般有两种常用的方法:#ifndef和#pragma once。两种方法正常情况下都可以避免头文件的重复include,但是它们之间还有一些区别。

本文将对这两种方法进行详细的对比分析,并给出代码示例。

知识点 #

#ifndef #

先看使用示例:

// File: myheader.h
#ifndef __MYHEADER_H__
#define __MYHEADER_H__

// 我们的代码

#endif // __MYHEADER_H__

它的工作原理是检查一个特定的宏(本例中对应__MYHEADER_H__)是否已经被定义。如果这个宏还没有被定义,那么#ifndef和#endif之间的代码就会被编译;如果这个宏已经被定义,那么#ifndef和#endif之间的代码就会被忽略。

优点 #

  1. 它可以处理多个include的情况,即使一个头文件被include多次,也只会被编译一次。
  2. 它是C和C++标准的一部分,它可以用在所有的C和C++编译器上。

缺点 #

  1. 需要为每个头文件定义一个唯一的宏,每个头文件都要写这样的代码,比较麻烦。
  2. 如果头文件的名字或者路径发生改变,一般需要更新对应的宏,维护起来比较困难,容易出bug,如果两个头文件一不小心使用了一样的宏…

#pragma once #

先看使用示例:

// File: myheader.h
#pragma once

// 我们的代码

#pragma once是一种特殊的预处理指令,它会告诉编译器只include这个头文件一次。

优点 #

  1. 使用起来非常简单,只需要在头文件的顶部添加一行#pragma once就可以。
  2. 即使文件名或者路径有改动,也无需定义新的指令名称,无需改动代码,维护成本低。
  3. 编译速度更快,这是一种高阶机制,部分编译器对此有优化。

缺点 #

  1. 它不是C/C++标准的一部分,虽然大部分的现代编译器都支持#pragma once,但是一些老的或者非主流的编译器可能不支持。

总结 #

#ifndef 属于C/C++标准的一部分,但使用起来麻烦,不利于维护。

#pragma once 使用起来简单,但不属于C++标准,非主流编译器可能不支持。

建议 #

目前主流编译器都已支持#pragma once,详见下图。如果你使用的是主流编译器,建议使用#pragma once,如果使用非主流编译器,或者非要追求标准,就使用#ifndef

主流编译器对#pragma once的支持情况

思考题 #

  • 你平时使用哪种方式?有遇到过不支持#pragma once的编译器吗?

参考资料 #