四种预编译命令:头文件包含,条件编译,宏替换和布局控制。
1.头文件包含
#include
文件分别用两种形式包含,一种将文件用“”包含,另一种用<>包含。
两种包含方式的不同之处在于,它们的查找策略不同。
#include<>包含的是库文件,会去系统库所在的文件目录下查找。
#include" "包含的是自己写的头文件,会先在所在的源文件的目录下查找,如果该头文件未找到,编译器就会像查找库函数一样再去系统库所在的文件下查找。
2.宏替换
1.宏替换的几种用法
a.定义常量
如#define cdz 50,则将在程序中搜索cdz并替换为50。但是注意,搜索的cdz只能是单独的单词,不能嵌入在单词中。如下:
#include<iostream>
#define cdz 50
int main
{
std::cout<<fcdzk<<std::endl;
}
b.定义语句
如:#define PFINT printf("hello world!\n");,将会在程序中搜索PFINT的单词,并换成后面的语句实行,将输出hello world!并换行。
c.定义函数
如:#define MAX(a, b) ((a)>(b)?(a):(b))
d.取消宏定义
如:#undef add,将会将之前的add的宏定义取消。
2.宏的特殊符号
a.#字符串化
#会将后面的变量转为一个字符串
#define PRT(exp) printf("%s\n",#exp);
#include<stdio.h>
int main()
{
PRT(FRI DAY)
return 0;
}
b.##连接
会将前后的两个符号连接在一起。如下:
#include<stdio.h>
#define ADD(value1, value2) num1##value2
int main()
{
int a = ADD(114, 514);
printf("%d \n", a);
return 0;
}
其他还有奇奇怪怪的各种宏,但没必要再去全面的了解,遇到之后百度即可。
3.条件编译
1.预定义符号
__FILE__ // 进行编译的源文件
__LINE__ // 文件当前的行号
__DATE__ // 文件被编译的日期
__TIME__ // 文件被编译的时间
__STDC__ // 如果编译器遵循 ANSI C,其值为1 ,否则未定义 ;
这些符号是c语言内置。如:
#include<iostream>
using namespace std;
int main()
{
cout<<__TIME__<<endl;
return 0;
}
2.包含头文件
1.#ifndef
#ifndef _MYHEADER_H
#define _MYHEADER_H
//头文件内容
#endif
第一次访问该头文件,会定义MYHEADER_H。然后才会执行头文件的内容。
之后在访问该文件,发现MYHEADER_H已经定义。因此头文件的内容将不再执行。
这种在多次包含头文件可能会用到,例如A头文件包含B头文件,C头文件包含B头文件,
如果不加上面的内容,B头文件将被包含两次,将会发生错误。
2.#progma once
目的是起到和#ifdef防止重复包含文件一样的作用。但入手点是物理文件下手,#progma once保证
同一物理文件不会被重复包含。
但如果同一头文件有多份拷贝,则不能保证不被重复包含。
但较#ifdef防止重复包含文件,带来的好处是,不必再费劲想个宏名了,当然也就不会出现宏名碰撞引发的奇怪问题。
3.包含内容
例如C++文件都会自动执行#define __cplusplus,因此我们想要仅在C++文件执行下面的内容,而不是C文件,就会像下面那样做:
#ifdef __cplusplus
//内容
#endif
4.布局控制
#ifndef UNIX
#error This software requires the UNIX OS.
#endif
这条指令主要是给出错误信息,上面的这个例子就是,如果没有在UNIX环境下,就会输出This software requires the UNIX OS.然后诱发编译器终止。所以总的来说,这条指令的目的就是在程序崩溃之前能够给出一定的信息。