预处理是C语言的一个重要知识点,能改善程序设计的环境,有助于编写易移植、易调试的程序。
一、文件的包含方式
#incude "文件名"
#include <文件名>
主要区别:
以<文件名>方式引用时,如果在VC++6.0编译,则会先在系统头文件目录中查找,若查找失败,再到当前目录查找,查不到则报错,在Linux环境下采用gcc进行编译,尽在系统头文件目录中查找,查不到报错。
以"文件名"引用的时候,不论在哪里编译,都先在当前目录查找,查找失败再到系统文件目录查找,再查不到则报错。
二、宏定义
#define 标识符 字符串
宏定义中的标识符都采用大写。
注意:1.宏替换不做语法检查,所以在使用时要小心
2.宏替换在文件开头部分,写在函数的花括号外边,作用域为其后的程序,直到#undef命令终止宏定义的作用域
3.不要在字符串中使用宏,如果宏名出现在字符串中将按字符串对待
(1)简单宏替换
简单宏替换在编程中通常用来定义常量
优点:减少不必要的修改,提升程序的可预读性,提升代码的可移植性。
注意:1.宏定义是简单的宏替换,不负责任何计算顺序
#include <stdio.h>
#define A 12+12
#define B 10+10
#define C (12+12)
#define D (10+10)
int main()
{
printf("%d\n",A*B);
printf("%d\n",C*D);
return 0;
}
很显然,他们的结果截然不同,第一个输出A*B=12+12*10+10,第二个输出C*D=(12+12)*(10+10)
可以通过#undef来设定宏名的作用域
(2)带参数的宏替换
一般形式:#include 宏名(参数表) 字符串
注意:1.宏名和参数表之间不能有空格
2.宏替换做替换,不做表达式和计算求解
3.宏展开使源程序变长,而函数调用不会
下面来看宏定义实现变参:
#include <stdio.h>
#include <stdlib.h>
#define print(...) printf(__VA_ARGS__)
int main()
{
print("hello world----%d\n", 1111);
system("pause");
return 0;
}
实现方式就是用“...”来替代“__VA_ARGS__”。
#define print(tem,...) fprintf(stdout,tem,##__VA_ARGS__)
在这个替换中,##的作用是使预处理器去除前面的逗号
(3)嵌套宏替换
嵌套宏替换就是在一个宏定义中使用另一个宏
#define N 3
#define N_CUBE N*N*N
三、条件编译指令的使用
方式一:当常量表达式为逻辑真时,编译一,否则编译二
#if 常量表达式
程序段1;
[#else
程序段2;]
#endif
方式二:如果标识符被#define定义过,则编译一,否则编译二
#ifdef 标识符
程序段1;
[#else
程序段2;]
#endif
方式三:如果标识符未被#define定义过,则编译一,否则编译二
#ifndef 标识符
程序段1;
[#else
程序段2;]
#endif
注意:不能在其后的常量表达式中使用变量,常量表达式不能是变量和含有sizeof等在编译时求值的操作符。
四、#pragma指令的使用
(1)#pragma message(“消息”)
可以在代码中输出想要的信息,也可以看某个宏是否被定义过
(2)#pragma once
若在头文件使用,表示头文件只使用一次
(3)#pragma hdrstop
编译头文件到此为止,后面无需在编译
(4)#pragma pack()
设置几字节对齐
例如:
#pragma pack(2):设置两字节对齐
#pragma pack(push):保存当前默认的字节对齐方式
#pragma pack(pop):恢复默认的字节对齐方式
(5)#pragma waning()
#pragma waning(disable: M N; once H; error: K)
表示不显露M,N的警告信息,H只显露一次,K作为一个错误来处理。