C/C++在预处理的时候,include相同的文件,预处理器会检查XXX是否有定义再决定要不要复制内容,重复包含会是编译器多检查几次而已。另外在使用增量编译的时候,这个文件变化,所有 include 这个文件的文件都需要重新编译,即使没有去使用里面的任何内容,所以重复包含最经常带来的错误就是重定义。
在用VC6.0向导生成的头文件中,经常可以看见如下的代码段:
#if !defined(AFX_RESIZABLELAYOUT_H__INCLUDED_)
#define AFX_RESIZABLELAYOUT_H__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
...
#endif // !defined(AFX_RESIZABLELAYOUT_H__INCLUDED_)
对于宏有基本了解的朋友应该都知道,头文件中如下的宏定义,是为了避免同样的头文件在同一个.C文件或者.CPP文件多次包含。
#if !defined(XXX)
#define XXX
#endif
由此可知这两种方式都可以很好的起到避免重复包含的作用,但是这两种有什么区别呢?
疑惑就此产生了,既然宏"#if !defined"已经有这个作用了,为何还要一个"#pragma once"呢?
其实虽然"#ifndef"和"#pragma once"都有避免重复包含的功能,但是在实现上还是有区别的。举一例如下:
// Test1.h
#ifndef __COMMENT_CONVERT_H__
#define __COMMENT_CONVERT_H__
...
#endif
// Test2.h
#pragma once
...
// Test.cpp
#include "Test1.h" //
#include "Test1.h" //
#include "Test2.h" //
#include "Test2.h" //
...
头文件Test1.h中用宏来避免重复,头文件Test2.h中用#pragma once来避免重复。编译Test.cpp,将需要打开Test1.h两次,第一次发现宏__COMMENT_CONVERT_H__没有定义,接着就处理宏定义;第二次打 开Test1.h时,发现宏__COMMENT_CONVERT_H__已经定义过了,编译器就会略过宏定义部分,直到处理完Test1.h末的#endif。
而由于头文件Test2.h使用#pragma once来避免重复定义的,在编译Test.cpp的过程中,Test2.h只会被打开一次,也就是处理到第3行的时候。因为Test2.h用的 是#pragma once,所以在处理完第3行后,编译器已经知道包含了一次Test2.h,在它(编译器)处理第4行代码时,发现Test2.h已经包含过了,忽略掉第 4行代码,也就不需要再次打开Test2.h进行判断了。
总结一下,除了#pragma once是微软编译器所特有的之外,用宏和#pragma once的办法来避免重复包含头文件,主要区别在于宏处理的方法会多次打开同一头文件,而#pragma once则不会重复打开,从而#pragma once能够更快速。
用更确切的语言总结一下就是:#pragma once指定当前文件在构建时只被包含(或打开)一次,这样就可以减少构建的时间,因为加入#pragma once后,编译器在打开或读取第一个#include 模块后,就不会再打开或读取随后出现的同#include 模块。