美文网首页
C语言预处理指令

C语言预处理指令

作者: AuglyXu | 来源:发表于2018-09-11 11:55 被阅读0次

    预处理指令

    宏定义

    • 宏定义会在预处理的时候, 用宏定义的值来替换宏的名称

    • 格式: #define 宏名称 宏值

    • 应用场景:

      • 企业开发分为开发阶段和部署阶段

      • 例如在程序开发中会用到很多的地址

    • 注意点:

      • 1.宏定义的后面不要写分号

      • 因为宏定义是单纯的替换, 会用宏的值替换宏名

      • 2.宏定义分为两种, 一种是不带参数的宏定义, 一种是带参数的宏定义

    不带参数的宏定义

    #define COUNT 5
    int main()
    {
       int ages[COUNT] = {1, 3, 5, 7, 9};
    // 除了可以动态计算数组的长度以外, 还可以利用宏定义
    //    int len = sizeof(ages) / sizeof(ages[1]);
    //    for(int i = 0; i < len; i++){
        for(int i = 0; i < COUNT; i++){
            printf("ages[%i] = %i\n", i, ages[i]);
        }
    return 0;
    }
    

    带参数的宏定义

    格式: #define 宏名称(参数) 参数

    #define SUM(a, b) a+b
    int main()
    {
        int num1 = 10;
        int num2 = 20;
        int res = SUM(num1, num2);
        printf("res = %i\n", res);
        return 0;
    }
    
    • 选择:

      • 如果函数的业务逻辑非常简单, 建议使用宏定义,因为宏定义的效率更高(原因:1.宏定义是在预处理的时候就执行了, 而函数是在运行的时候才会执行.2.宏定义只会做简单的替换, 而函数还需要分配内存空间)

      • 如果业务逻辑比较复杂, 那么还是建议使用函数

    • 注意点:

      • 1.宏的值的每个参数都需要加上()

      • 2.宏的值的结果也需要加上()

    #define JF(a) ((a)+(a))
    int main()
    {
        int num = 10;
        int res = JF(5 + 5) / JF(2 + 2);
        printf("res = %i\n", res);
        return 0;
    }
    

    宏定义的作用域

    • 宏定义的作用域和全局变量很像, 但是可以通过#undef宏名提前结束

    • 作用域是从定义的那一行开始, 直到文件末尾


    条件编译

    • 格式:
    #if
    #else
    #endif
    
    • 条件编译和if else区别
      1.if else语句是在程序运行的时候执行的而#if #else #endif是在预处理的时候执行的
      2.if else语句所有的代码都会编译到程序中而#if #else #endif中只有满足条件的语句才会编译到程序中

    • 注意点:
      1.---> #if 和 #endif 可以组成一对 #if #else #endif 可以组成一对 #if #elif #else #endif 可以组成一对, 其中#elif可以有一个或对个
      2.--->无论怎么组合#endif都不可以省略
      3.--->条件编译中不能获取变量的值
      4.--->条件编译一般是配合宏定义来使用,因为宏定义和条件编译都是在预处理的时候执行的

    #include <stdio.h>
    /*
    #define DEBUG 0
    
    #if DEBUG == 1
    #define URL "127.0.0.1"
    #else
    #define URL "www.it666.com"
    #endif
    */
    
    #define DEBUG 1
    
    #if DEBUG == 1
    #define NJLOG(format, ...) printf(format, ##__VA_ARGS__)
    #else
    #define NJLOG(format, ...)
    #endif
    
    int main()
    {
        /*
         * 在开发阶段, 我们经常使用打印的形式来调试程序
         * 但是打印其实是非常消耗性能的, 所以在部署阶段都需要去除打印
         */
    //    printf("%s\n", URL);
    //    printf("%s\n", URL);
    //    printf("%s\n", URL);
    //    printf("%s\n", URL);
    //    printf("%s\n", URL);
    
        for(int i = 0; i < 100; i++){
            NJLOG("i = %i\n", i);
        }
        return 0;
    }
    
    • 第二种格式:
         * #ifdef #else #endif
         * #ifdef作用: 判断是否定义某一个宏
         *
         * #ifndef #else #endif
         * #ifndef作用: 判断是否没有定义某一个宏
    

    文件包含

    1.--->#include <>

    <> 会先从编译器的环境中查找对应的文件, 如果没有再从系统的环境中查找对应的文件

    2.--->#include ""

    "" 会先从当前项目环境中查找对应的文件, 如果没有再从编译器的环境中查找对应的文件, 如果还没有再从系统的环境中查找对应的文件

    3.---> #include作用:

    将指定文件中的代码原方不动的拷贝到#include的位置

    • 注意点:
      1.已知函数的定义不可以重复, 但是函数的声明可以重复
      2.但是如果重复声明函数, 或者重复导入.h文件会影响编译器的编译效率
      3.所以在C语言中引入了头文件卫士的概念, 专门用于解决重复导入
      4.不要出现循环包含(A文件包含B文件, B文件又包含A文件)

    typedef

    • 作用:给数据类型起别名

    • 格式:typedef 原来的类型名称 新的类型名称;

    • 注意点:

      • typedef相当于给人起了一个外号, 人还是那个人, 只不过多了一个名称而已

      • 所以typedef不是定义一个新的数据类型, 而是定义一个新的名称而已

     typedef int ZHENGSHU;
        // 2.给别名再起别名
        typedef ZHENGSHU DOUBI;
    
        int num = 9;
        printf("num = %i\n", num);
    
        ZHENGSHU value = 666;
        printf("value = %i\n", value);
    
        DOUBI i = 888;
        printf("i = %i\n", i);
    
        ZS j = 123;
        printf("j = %i\n", j);
    
    • 应用场景

    • typedef一般用于给复杂的数据类型起别名, 方便将来使用

      1. 结构体
     // 2.给结构体起别名
        struct Person{
            String name;
            int age;
        };
        // 2.1先定义结构体类型, 再给结构体类型起别名
        typedef struct Person ps;
        struct Person p;
        // 2.2定义结构体类型的同时, 给结构体类型起别名
        typedef struct Person{
            String name;
            int age;
        } ps;
         ps p = {"lnj", 58};
        // 2.3定义结构体类型的同时, 给结构体类型起别名, 并且省略原有类型的名称
        // 企业开发的写法
        typedef struct{
            String name;
            int age;
        } Person;
    
        //  struct Person p = {"lnj", 58};
        Person p = {"lnj", 58};
        printf("name = %s\n", p.name);
    

    1. 指针
     typedef char* String;
        String name = "it666";
        printf("name = %s\n", name);
    

    1. 指向函数的指针
        // 注意点: 如果给指向函数的指针起别名, 那么指针名称就是别名
        // 企业开发经常使用, 随处可见
        typedef int (*funP)(int, int);
        funP p1 = &sum;
        funP p2 = &minus;
    

    typdef和宏定义的区别

    如果是要给数据类型起别名, 那么一律用typedef即可
    注意点:

    #define ZIFUCHUAN char*
        // ZIFUCHUAN n3, n4;
        // char* n3, n4;
        // 只有n3是指针, 而n4是字符
        ZIFUCHUAN n3, n4;
    
    //而n1,n2都是指针
     typedef char* String;
    //    String name2 = "zs";
        String n1, n2;
        n1 = "zs";
        n2 = "ww";
        printf("n1 = %s\n", n1);
        printf("n2 = %s\n", n2);
    

    const

    • const 格式: const 数据类型 变量名称;

    • 注意点:

      • const可以写在数据类型的前面, 也可以写在数据类型的后面
      • 对于基本数据类型来说, 写在数据类型的前面和后面没有任何区别
      • 但是对于指针来说, 写在数据类型的前面和后面就有区别了
    • const和指针

      • const如果写在指针数据类型左边, 那么代表指针指向的内存空间不能修改, 但是指针的指向可以修改
      • const如果写在指针数据类型右边, 那么代表指针指向的内存空间不能修改, 但是指针的指向可以修改
      • const如果写在指针星号右边, 那么代表指针指向的内存空间可以修改, 但是指针的指向不可以修改

    相关文章

      网友评论

          本文标题:C语言预处理指令

          本文链接:https://www.haomeiwen.com/subject/ubpygftx.html