• #宏_预处理


    #宏_预处理

    #开头都是预处理指令,条件表达式必须在预处理里面,所以表达式必须是宏表达式

    1 #define宏定义

    替换

    2 #if...#elif...#else...#endif条件编译

    中英文

    3 #ifdef...#endif

    4 #ifndef...#endif

    5 #include文件包含

    包含

    6

    __DATE__

    进行预处理的日期(“Mmm dd yyyy”形式的字符串文字)

    __FILE__

    代表当前源代码文件名的字符串文字

    __FUNCTION__

    __func__

    代表所在函数名

    __LINE__

    代表当前源代码中的行号的整数常量

    __TIME__

    源文件编译时间,格式“hh: mm: ss”

     

    1 宏定义

    软件工程规定,宏定义用英文大写

    define不会进行类型检查,只会替换,所以某些场合会出错。

    尽量不用define,用const,const初始化的时候,会自动进行类型转换,会有类型检查

     1 #define _CRT_SECURE_NO_WARNINGS
     2 
     3 #include <stdio.h>
     4 #include <stdlib.h>
     5 
     6 #define M 10.0
     7 
     8 main()
     9 {
    10     const int N = 10.9;
    11 
    12     printf("%d
    ", M);//define不会进行类型检查,只会替换,所以某些场合会出错。
    13 
    14     printf("%d
    ", N);//尽量不用define,用const,const初始化的时候,会自动进行类型转换,会有类型检查
    15 
    16     system("pause");
    17 }

    宏替换只能替换单独的标识符,连着一起的无法替换,或者字符串内部的也无法替换

     1 #define _CRT_SECURE_NO_WARNINGS
     2 
     3 #include <stdio.h>
     4 #include <stdlib.h>
     5 
     6 #define X 10
     7 
     8 main()
     9 {
    10     printf("%d
    ", X);
    11 
    12     int XX = 100;
    13 
    14     printf("%d
    ", XX);//宏替换只能替换单独的标识符,连着一起的无法替换,或者字符串内部的也无法替换
    15 
    16     system("pause");
    17 }

    输出结果:

    10
    100
    请按任意键继续. . .

    宏的作用域,就是它所在的.c源文件

    限定宏定义的作用域 #define M 10

    终结宏定义,需要#undef

     1 #define _CRT_SECURE_NO_WARNINGS
     2 
     3 #include <stdio.h>
     4 #include <stdlib.h>
     5 
     6 #define M 10
     7 
     8 void out()
     9 {
    10     printf("%d
    ", M);
    11 }
    12 
    13 #undef M//限定宏定义的作用域 #define M 10
    14 //终结宏定义,需要#undef
    15 
    16 main()
    17 {
    18     out();
    19 
    20     //printf("%d
    ", M);
    21 
    22     system("pause");
    23 }

    带参数的宏定义

    求出两个整数的最小值

    面试题,如果取两个数之间最小的数

    面试标准答案,看你的逻辑是否严密

    min(x,y)宏参数表的参数,不可以加上括号(),但是后面的宏调用可以加上括号()

     1 #define _CRT_SECURE_NO_WARNINGS
     2 
     3 #include <stdio.h>
     4 #include <stdlib.h>
     5 
     6 //面试题,如果取两个数之间最小的数
     7 //面试标准答案,看你的逻辑是否严密
     8 //min(x,y)宏参数表的参数,不可以加上括号(),但是后面的宏调用可以加上括号()
     9 
    10 #define min(x,y) ((x)>(y))?(y):(x)
    11 
    12 main()
    13 {
    14     printf("%d
    ", min(1 + 2, 2 + 9));
    15 
    16     system("pause");
    17 }

     传递的参数,自动加上双引号"",让其变成一个字符串

    #自动加上双引号""

     1 #define _CRT_SECURE_NO_WARNINGS
     2 
     3 #include <stdio.h>
     4 #include <stdlib.h>
     5 
     6 #define go(x) system(#x)
     7 //传递的参数,自动加上双引号"",让其变成一个字符串
     8 //#自动加上双引号""
     9 
    10 main()
    11 {
    12     system("notepad");
    13 
    14     go(calc);
    15 
    16     system("pause");
    17 }

    #define就是替换,没有数据类型,无法安全检查

    conse是有数据类型的,可以根据数据类型进行安全检查

    发行数据类型不匹配的时候,会发出警告或者转换

    能转换的时候就自动进行数据类型转换,不能转换就发出警告

     1 #define _CRT_SECURE_NO_WARNINGS
     2 
     3 #include <stdio.h>
     4 #include <stdlib.h>
     5 
     6 #define X 10.0
     7 
     8 const int num = 10.0;
     9 
    10 //#define就是替换,没有数据类型,无法安全检查
    11 
    12 //conse是有数据类型的,可以根据数据类型进行安全检查
    13 //发行数据类型不匹配的时候,会发出警告或者转换
    14 //能转换的时候就自动进行数据类型转换,不能转换就发出警告
    15 
    16 main()
    17 {
    18     printf("%d
    ", sizeof(X));
    19 
    20     printf("%d
    ", sizeof(num));
    21 
    22     system("pause");
    23 }

    2 条件编译

    #if...#elif...#else...#endif

    if...else if...else

    功能是一样的,但是时间开销不一样

    编译就是翻译成机器码0,1

    #if...#elif...#else...#endif只编译符合条件的语句,所以有效减少被编译的语句,缩短源码的长度,达到缩短程序执行时间的目的。#if...#elif...#else...#endif需要判断表达式,所以我们定义宏必须给出值,否则无从判断。

    if...else if...else会编译所有的代码,源码会较长,编译时间也会较长,程序体积会大,占内存也会大,运行时间会较长。

    什么时候需要条件编译?

    例如发布一个产品,如果有多个语言版本,可以有效减少体积。

    一份源代码可以同时编译英文或者中文,有效减少体积。

      

     1 #define _CRT_SECURE_NO_WARNINGS
     2 
     3 #include <stdio.h>
     4 #include <stdlib.h>
     5 #include <windows.h>
     6 
     7 //多分支条件编译,一般用于软件的国际化
     8 //有效减少体积,一份源码可以编译很多个版本
     9 //if...else if...else也可以实现一样的效果,但是体积太大
    10 
    11 #define language 'e'
    12 //c中文,e英文,k韩文,j日本,r俄罗斯文,
    13 
    14 main()
    15 {
    16 #if language == 'c'
    17     MessageBoxA(0, "你好中国", "你好中国", 0);
    18 #elif language == 'e'
    19     MessageBoxA(0, "hello world", "hello world", 0);
    20 #elif language == 'k'
    21     MessageBoxA(0, L"안녕하세요 중국", L"안녕하세요 중국", 0);//L宽字符,韩文需要用宽字符,宽字符一般用于软件国际化
    22 #elif language == 'j'
    23     MessageBoxA(0, "こんにちは中国", "こんにちは中国", 0);
    24 #else
    25     MessageBoxA(0, "привет Китай", "привет Китай", 0);
    26 #endif
    27 
    28     system("pause");
    29 }

    3 #ifdef...#endif

    ifdef M检测一下一个宏是否定义,定义就执行某个操作

    否则就不执行

     1 #define _CRT_SECURE_NO_WARNINGS
     2 
     3 #include <stdio.h>
     4 #include <stdlib.h>
     5 
     6 //开启或者关闭某个功能
     7 #define M
     8 
     9 main()
    10 {
    11     //ifdef M检测一下一个宏是否定义,定义就执行某个操作
    12     //否则就不执行
    13 
    14 #ifdef M
    15     system("title hello");
    16 #endif
    17 
    18     system("pause");
    19 }

    4 #ifndef...#endif

    这是"if not defined"的简写,是宏定义的一种,它是可以根据是否已经定义了一个变量来进行分支选择,一般用于调试等等。实际上确切的说这应该是预处理功能中三种(宏定义,文件包含和条件编译)中的第三种----条件编译。

     1 #define _CRT_SECURE_NO_WARNINGS
     2 
     3 #include <stdio.h>
     4 #include <stdlib.h>
     5 #include <windows.h>
     6 
     7 main()
     8 {
     9 #ifndef M
    10     MessageBoxA(0, "M没有定义", "M没有定义", 0);
    11 #endif
    12 
    13     system("pause");
    14 }

    如果有多个头文件,其中一个头文件A定义了整型变量,另外一个头文件B包含了头文件A,同时源文件也包含了以上AB两个头文件,这样将会重复定义整型变量。

    解决办法:在A头文件中,定义NUM

    1 #ifndef NUM
    2 #define NUM
    3 
    4 int num = 10;
    5 
    6 #endif

    如果有多个头文件,其中一个头文件A定义了函数,另外一个头文件B包含了头文件A,同时源文件也包含了以上AB两个头文件,这样将会重复定义函数。

    解决办法:在A头文件中,定义GO

    1 #ifndef GO
    2 #define GO
    3 
    4 void go()
    5 {
    6 
    7 }
    8 
    9 #endif

    如果有多个头文件,其中一个头文件A定义了结构体,另外一个头文件B包含了头文件A,同时源文件也包含了以上AB两个头文件,这样将会重复定义结构体。

    解决办法:在A头文件中,定义INFO

     1 //规避重复包含
     2 #ifndef INFO//检测是否定义INFO,没有定义就执行下面一段
     3 #define INFO//定义INFO宏
     4 
     5 struct info
     6 {
     7     char name[20];
     8     int num;
     9 };
    10 
    11 #endif

    5 文件包含

      

    #include <只搜索系统的目录>

    #include "先搜索源文件目录,再搜索系统的目录"

      

    6

    __DATE__

    在源代码中插入当前编译日期〔注意和当前系统日期区别开来〕

    __FILE__

    在源代码中插入当前源代码文件名

    __FUNCTION__

    __func__

    代表所在函数名

    __LINE__

    在源代码中插入当前源代码行号

    __TIME__

    在源代码中插入当前编译时间〔注意和当前系统时间区别开来〕

     1 #define _CRT_SECURE_NO_WARNINGS
     2 
     3 #include <stdio.h>
     4 #include <stdlib.h>
     5 
     6 void run()
     7 {
     8     printf("当前文件名%s
    ", __FILE__);
     9 
    10     printf("当前语句在%d行
    ", __LINE__);
    11 
    12     printf("当前函数名%s
    ", __FUNCTION__);
    13 
    14     printf("编译日期%s编译时间%s
    ", __DATE__, __TIME__);
    15 }
    16 
    17 //当代码出错的时候,可以提示代码错误在哪一行
    18 
    19 main()
    20 {
    21     printf("当前文件名%s
    ", __FILE__);
    22 
    23     printf("当前语句在%d行
    ", __LINE__);
    24 
    25     printf("当前函数名%s
    ", __FUNCTION__);
    26 
    27     printf("编译日期%s编译时间%s
    ", __DATE__, __TIME__);
    28 
    29     run();
    30 
    31     system("pause");
    32 }

    进行软件测试,还有软件测试,需要定位错误,所以在错误的处理语句中,需要加上宏

     1 #define _CRT_SECURE_NO_WARNINGS
     2 
     3 #include <stdio.h>
     4 #include <stdlib.h>
     5 
     6 main()
     7 {
     8     int num1 = 100, num2 = 0;
     9 
    10     if (num2 == 0)
    11     {
    12         printf("被除数不能为0,%s,%s,%d
    ", __FILE__, __FUNCTION__, __LINE__);
    13     }
    14 
    15     //进行软件测试,还有软件测试,需要定位错误,所以在错误的处理语句中,需要加上宏
    16 
    17     system("pause");
    18 }

    C++调试技能

     1 #include <iostream>
     2 
     3 #define N//定义N
     4 
     5 void main()
     6 {
     7     int num(10);
     8 
     9 #ifdef M//没有定义M,所以没有执行#ifdef...#endif之间的语句
    10     static_assert(sizeof(num) >= 4, "代码报错 num");
    11 #endif
    12 
    13 #ifdef N//有定义N,所以执行#ifdef...#endif之间的语句
    14     static_assert(sizeof(num) >= 4, "代码报错 num");
    15 #endif
    16 
    17     std::cout << __DATE__ << std::endl;//在源代码中插入当前编译日期〔注意和当前系统日期区别开来〕
    18 
    19     std::cout << __FILE__ << std::endl;//在源代码中插入当前源代码文件名
    20 
    21     std::cout << __FUNCTION__ << std::endl;//代表所在函数名
    22 
    23     std::cout << __func__ << std::endl;//代表所在函数名
    24 
    25     std::cout << __LINE__ << std::endl;//在源代码中插入当前源代码行号
    26 
    27     std::cout << __TIME__ << std::endl; //在源代码中插入当前编译时间〔注意和当前系统时间区别开来〕
    28 
    29     system("pause");
    30 }
  • 相关阅读:
    leetcode 之Binary Tree Postorder Traversal
    关于java中this的一些总结
    Javascript的匿名函数与自执行
    js 闭包学习笔记
    滚动条到底自动加载数据
    AMD:异步模块定义
    Sass、LESS 和 Stylus
    【原创】Mysql设置自增长主键的初始值
    -webkit-animation的使用
    CSS滤镜
  • 原文地址:https://www.cnblogs.com/denggelin/p/5544638.html
Copyright © 2020-2023  润新知