为避免同一个文件被包含(include)多次, C/C++中有两种实现方式:#ifdef 和#pragma once 。

在能够支持这两种方式的编译器上,二者并没有太大的区别。但二者仍然有一些细微的区别。

1. #pragma once方式


1.1. 使用方法

#pragma once
 
// content of this file

1.2. 意义


#pragma once 是编译器相关,移植型差,有些编译器支持,有些编译器不支持,比如:gcc,vs 编译器支持,bcc 编译器不支持。由编译器提供保证,同一个文件不会被包含多次。这里所说的“同一个文件”是指物理上的一个文件,而不是指内容相同的两个文件。不用像使用 #ifdef 一样想宏名了,当然也就可以避免宏的名字冲突问题。缺点:如果某个头文件有多份拷贝,本方法不能保证他们不被重复包含。

2 #ifndef 方式


2.1. 使用方法


#ifndef xxxx
#define xxxx
 
// content
 
#endif // xxxx


2.2. 意义


#ifndef 是 C 语言相关的,通过宏定义避免文件多次编译。所以在所有支持C/C++ 语言的编译器上都是有效的。跨平台移植性好。它依赖于宏名避免被 include 多次,如果宏已经定义了,#ifndef 将不满足条件,在预处理时,直到 #endif 处的代码会被直接删除。这不光可以保证同一个文件不会被包含多次,也能保证内容完全相同的两个文件不会被同时包含,只认识宏,不管是不是相同的代码或者这是哪个文件。为了保证不同头文件中的宏名不冲突,使用文件名定义宏,例如文件名为 abc.h,就定义宏为 _ABC_H_。

3. 区别


3.1. 语意区别

  • #pragma once 针对文件,它告诉编译器,本文件只编译一次。
  • #ifndef…#define…#endif 是针对文件中的某一个标号而言的,防止三个指令间包含的内容的重复性处理,更灵活。

#ifndef的方式依赖于宏名字不能冲突,这不光可以保证同一个文件不会被包含多次,也能保证内容完全相同的两个文件不会被不小心同时包含。当然,缺点就是如果不同头文件的宏名不小心"撞车",可能就会导致头文件明明存在,编译器却硬说找不到声明的状况

#pragma once则由编译器提供保证:同一个文件不会被包含多次。注意这里所说的"同一个文件"是指物理上的一个文件,而不是指内容相同的两个文件。带来的好处是,你不必再费劲想个宏名了,当然也就不会出现宏名碰撞引发的奇怪问题。对应的缺点就是如果某个头文件有多份拷贝,本方法不能保证他们不被重复包含。当然,相比宏名碰撞引发的"找不到声明"的问题,重复包含更容易被发现并修正

3.2. 性能区别


使用 #ifndef,编译器每次看到 #include 这个文件都需要读入文件,解析代码,效率低

而使用 #pragma once 编译器根本不会重复打开文件,大大提高效率。

3.3. 可移植性方面


#pragma once 依赖于编译器,可移植性较差
#ifndef…#define…#endif 是 C/C++ 标准中的一部分,支持 C/C++ 的编译器都能使用,可移植性更高。

3.4 编码风格上

  • 使用 #pragma once 的代码简洁
  • #ifndef 定义如下:#ifndef…#define…#endif

                          

更多推荐