条件编译用于文件包含保护
1.条件编译(Conditional Compilation)命令常用的形式:
- 当所指定的标识符已经被#define命令定义过,则只编译程序段1,否则编译程序段2,
#ifndef
则相反, #endif用来限定#ifdef命令的范围。其中#else部分可以省略。
#ifdef 标识符
程序段1
#else
程序段2
#endif
- 类似地,如下形式中,根据指定的表达式值来选择所编译的程序段。
#if 表达式
程序段1
#else
程序段2
#endif
2.头文件包含保护(Include guard)
header files are #included and not compiled, whereas source files are compiled and not #included.
如果在源文件中重复#include同一个头文件,很可能会出现编译错误,一个简单的例子:
// myclass.h
class MyClass
{
void DoSomething() { }
};
// main.cpp
#include "myclass.h" // define MyClass
#include "myclass.h" // Compiler error - MyClass already defined
这种情况很常见,只不过不像上面那么明显,更一般的情况是,#inlclude多个包含了同样头文件的头文件:
// x.h
class X { };
// a.h
#include "x.h"
class A { X x; };
// b.h
#include "x.h"
class B { X x; };
// main.cpp
#include "a.h" // also includes "x.h"
#include "b.h" // includes x.h again! ERROR
鉴于此,可能得到建议:not to put #include in header files。然而,这不是一个好的建议。事实上,头文件中使用#inlude命令并没有什么问题,并且通常是很常用的。两点需要注意:
- Only #include things you need to include.
- Guard against incidental multiple includes with include guards.
Include Guard技术可以解决上面的问题,例子:
//x.h
#ifndef X_H // if x.h hasn't been included yet...
#define X_H // #define this so the compiler knows it has been included
class X { };
#endif
根据条件编译很容易理解,x.h在第一次被included的时候,将定义标识符 _X_H_INCLUDED,这样的话,如果x.h再次被included,编译器则会跳过整个头文件(#ifndef和#endif之间的程序段),不编译这部分内容。这样就解决了上述重复包含带来的重定义问题。
一个重要的C++软件工程概念,又称“预处理器封套”,在头文件中使用预处理器封套,从而避免头文件中的代码被多次包含到同一个源文件中的情况。由于一个类只能被定义一次,因此使用这样的预处理器指令阻止了重复定义的错误。
预处理指令中符号常量命名的通常约定是将头文件名大写,其中的dot用下划线代替。