Day12

预处理指令

预处理指令:
文件包含 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;
}

你可能感兴趣的:(Day12)