预处理指令
预处理指令:
文件包含 include
宏定义 #define
条件编译 #if #else #endif
宏定义
- 基本格式
#include
#define URL "www.it666.com"
int main()
{
/*
* 宏定义:
* 宏定义会在预处理的时候,用宏定义对应的值来替换宏
* 宏定义格式:
* #define 宏名称 宏值
* 应用场景:
* 企业开发中分为开发和部署阶段
* 例如在程序开发中会用到很多地址,用来替换更改的地址
* 注意点:
* 1.宏定义的后面不要写分号,因为宏定义是单纯的替换
* 2.宏定义分为两种,一种是不带参数的宏定义,一种是带参数的宏定义
*/
printf("%s\n", URL);
return 0;
}
- 不带参数的宏定义
#define URL "www.it666.com" //简单是替换
- 带参数的宏定义
#include
#define SUM(a, b) ((a)+(b))
#define PF(a) (a)*(a)
int main()
{
/*
* 带参数的宏定义
* #define 宏名字(参数) 参数
* 一些简单的函数,除了可以使用函数来封装外,还可以使用宏定义
* 注意点: 宏定义无论有没有参数都是单纯的替换
*
* 在企业开发中如何选择宏定义还是函数
* 1. 如果是函数的业务逻辑非常简单,建议使用宏定义,因为宏定义效率更高
* 宏定义是在预处理的时候就执行了,函数是在运行的时候才执行,而且
* 宏定义只会简单替换,函数还需要分配内存空间
*
* 2.业务逻辑复杂,就使用函数
*
* 注意点:
* 1. 每个参数都要加上()
* 2. 结果也需要加上()
*/
printf("%i\n", SUM(10, 20));
return 0;
}
- 宏定义的作用域
#include
#define COUNT 666
int main()
{
/*
* 宏定义的作用域
* 和全局变量很像,都是从定义的那行开始,直到文件末尾,但是可以提前结束
* 通过 #undef 宏名 来提前结束宏的作用域
*
*/
printf("%i\n",COUNT); //可以运行
test();
return 0;
}
#undef COUNT //宏定义的作用域在这一行结束,后面的访问不到
void test(){ //可以运行
printf("%i\n",COUNT);
}
条件编译
- 基本格式
#include
#define SCORE 100
int main()
{
/*
* 条件编译
* 格式:
* #if #else #endif 可以组成一对
* #if 和 #endif 可以组成一对
* #if #elif #else #endif 可以组合,其中#elif 可以有一个或者多个
* 无论怎么组合, #endif都不可以省略,作用是告诉编译器条件编译的结束位置
*
*
* 条件编译和 if条件判断很像,但是也有区别
* 1. if else是在程序运行的时候执行
* #if #else #endif 是在预处理的时候执行
* 2. if else语句中所有的代码都会被编译到程序中
* #if #else #endif条件编译 只有满足条件的语句才会被编译到程序中
*
*/
/*
* 注意点:
* 条件编译中不能获取变量的值,因为变量是在程序执行的时候才有的,而条件
* 编译是在预处理的时候就执行了
* 条件编译一般都会配合宏定义来使用,因为两者都是在预处理中执行
*/
#if 100 == SCORE
printf("100分");
#else
printf("不是100分");
#endif
return 0;
}
- 应用场景
用来替换打印语句,因为打印语句很消耗性能
#include
// 替换打印的条件编译
#define DEBUG 0
#if DEBUG == 1
#define NJLOG(format, ...) printf(format, ##__VA_ARGS__)
#else
#define NJLOG(format, ...)
#endif
int main()
{
/*
* 在开发阶段,经常使用打印的形式来调试程序
* 但是打印非常消耗性能,所以再部署阶段都需要去除打印
*/
for(int i = 0; i < 10; i ++){
NJLOG("i = %i\n", i);
}
return 0;
}
- 条件编译的另外两种格式
条件编译的另外两种格式
第一种格式
#ifdef #else #endif 作用是判断是否定义了某一个宏,定义了为真
第二种格式
#ifndef #else #endif 作用是判断是否没有定义了某一个宏,没有定义了为真
条件包含
注意点: 头文件卫士
#include
// 1.判断有没有定义名称叫做LNJ的宏
#ifndef LNJ
// 2.如果没有定义就会进入到这里面
// 2.定义一个叫做LNJ的宏
#define LNJ
int sum(int num1, int num2);
#endif
// 1.判断有没有定义名称叫做LNJ的宏
#ifndef LNJ
// 2.由于前面已经定义了, 所以条件不满足, 所以就不会进入这里面了
#define LNJ
int sum(int num1, int num2);
#endif
int main()
{
/*
* 条件包含 #include
* #include <>
* 会先从编译器的环境中查找对应的文件,如果没有再从系统的环境中查找对应文件
* #include ""
* 会先从当前的项目环境中查找对应的文件, 如果没有再从编译器的环境中查找对应的文件
* 如果还没有再从系统的环境中查找对应文件
*
* #include 作用: 将指定文件中的代码原封不动的拷贝到#include位置
* #include执行时间: 预处理时候执行
*/
/*
* 注意点:
* 已知函数的定义不可以重复,但是函数的声明可以重复
* 如果函数的声明被include导入多次,那么会影响程序的编译效率
* 所以在C语言中引入了头文件卫士的概念,专门用于解决重复导入的问题
*
*/
return 0;
}