# 预处理器
## 一、预编译
1、什么是预编译,何时需要预编译?
预编译也叫预处理,指的是程序编译前的代码文本处理工作。主要是以#号书写的预编译指令。这些#号的代码可以分三类:#include包含代码;#define宏定义的替换;#ifndef条件编译。
- 总是使用不经常改动的大型代码体;
- 程序由多个模块组成,所有模块都使用一组标准的包含文件和相同的编译选项,在此情况下可以将所有包含文件预编译为一个预编译头。
2、标准头文件共同的代码结构
```c++
#ifndef WANGYUEDONG_H_ //条件编译为了防止该头文件被包含多次
#define WANGYUEDONG_H_
extern "C" { //实现C++与C的混合编程
#include "cExample.h"
}
#endif
```
extern "C" 声明实现C++与C的混合编程。C++作为面向对象的语言,支持函数重载,而过程式编程C则不支持函数重载。同一函数被C++编译和C编译后在symbol库中的名字不同。例如,假设某个函数的原型为:
```c++
void foo(int x, int y);
```
该函数被C编译器编译后在symbol库中名字为 `_foo` ,而C++编译器的名字为 `_foo_int_int` 的名字。C++编译后的函数同时带有了函数名和参数数量和参数类型信息,C++就是通过这种机制来实现函数重载的。
为了实现C和C++的混合编程,C++提供了C连接交换指定符号extern "C" 来解决名字匹配问题,函数声明前加上extern "C" 后,则编译器会按照C的方式编译,这样C就可以调用C++的函数了。
3、对于频繁使用的短小函数
在C中,对于频繁使用的短小函数用宏定义;
在C++中,对于频繁使用的短小函数用inline内联函数。
## 二、define表达式
define表达式直观好用,需要注意的是语法规则:无分号;可使用括号;防止溢出;小心输入自加自减的参数。
1、用预处理指令声明一个常数
```c++
#define SECONDS_PER_YEAR (60*60*24*365)UL //C编程中,C++常用const变量来表示
```
懂得预处理器将计算常数表达式的值,直接写出怎么样计算一年中有多少秒而不是计算出实际的值,是更清晰而没有代价的。这个表达式将使一个16位机的整型数溢出-因此要用到长整型符号L,告诉编译器这个常数是无符号的长整型数。
2、标准的宏定义,这个宏输入两个参数并返回较小的一个。
```c++
#define MIN(A, B) ((A)<=(B)?(A):(B))
```
3、已知一个数组table,用一个宏定义,求出数据的元素个数
```c++
#define NTBL (sizeof(table)/sizeof(table[0]))
```
4、用宏定义实现swap
```c++
#define SWAP(x, y) {x+=y; y=x-y; x=x-y;} //这个算法很巧妙的避免了多余的变量,节省不必要的空间
```
5、一语句实现x是否为2的若干次幂的判断
```c++
#define is2*n(x) ((x&(x-1))? 0:1)
int main(void){
int m = 512;
cout << ((m&(m-1))? false: true) << endl;
return 0;
}
```
## 三、预处理器和宏
写在预处理器定义中的语句实际上就是宏定义,在本工程中的所有文件中都加上同样的宏定义。
```C++
//预处理器定义中: WIN32;_DEBUG;%(PreprocessorDefinitions)
#define WIN32
#define _DEBUG
#define _UNICODE
```
这样,就可以达到一个多一个同一个代码在不同的配置环境在编译的结果文件不一样,从而实现跨平台。比如,在VC中,因为要有的环境是UNICODE,有些则不是,同一份代码为了在两种环境下都可以用,那么就会有以下宏定义(其实这就是twhar.h中的代码)
```C++
#ifdef _UNICODE
typedef wchar_t TCHAR;
#define __T(x) L##x
#define _T(x) __T(x)
#else
#define __T(x) x
typedef char TCHAR;
#endif
```
当你的环境中写了UNICODE时,这一段就会编译:
```C++
#define __T(x) L##x
#define _T(x) __T(x)
```
如果没有写UNICODE,那么上面这段就不编译,而是下面这段被编译:
```C++
#define __T(x) x
```
这样,只要你的字符串用了_T("somechar"),那么,在有UNICODE的时候,就是L"somechar";在没有UNICODE在时候,就是它本身"somechar"了。