• C语言预处理命令


    预处理的概念

    以"#"号开头的就是预处理命令,在源程序中这些命令都放在函数之外,而且一般都放在源文件的前面,它们称为预处理部分
            所谓预处理是指在进行编译的第一遍扫描(词法扫描和语法分析)之前所作的工作,预处理是C语言的一个重要功能,它由预处理程序负责完成.当对一个源文件进行编译时,系统将自动引用预处理程序对源程序中的预处理部分作处理,处理完毕自动进行对源程序的编译
            C语言提供了多种预处理功能,如:宏定义、文件包含、条件编译等.合理地使用预处理功能编写的程序便于阅读、修改、移植和调试,也有利于模块化程序设计。
    

    宏及条件编译:

    宏的概念

    被定义为"宏"的表示符称为"宏名"。在编译预处理时,对程序中所出现的"宏名",都用宏定义中的字符串去代换,这称为"宏代换“或”宏展开"
            宏定义是由源程序中的宏定义命令完成的,宏代换是由预处理程序自动完成的.在C语言中,"宏分为有参和无参数两种"
            
            无参宏的宏名后不带参数,其定义的一般形式为:
                #define 标示符 字符串
     
                # 表示这是一条预处理命令,凡是以"#"开头的均为预处理命令
                define 为宏定义命令
                标示符  为所定义的宏名
                字符串  可以是常数、表达式、格式串等
    

    注意事项:

     1.习惯上宏名用大写字母表示,以便于与变量区别,但也允许用小写字母
     
             2.宏定义时用宏名来表示一个字符串,在宏展开时又以该字符串取代宏名,这只是一种简单地代换,字符串中可以含任何字符,可以是常量,也可以是表达式,预处理程序对它不作任何检查.如有错误,只能在编译已被宏展开后的源程序时发现
             3.宏定义不是说明或语句,在行末不必加分号,如加上分号则连分号也一起置换
             4.宏定义必须写在函数之外,其作用域为宏定义命令到源程序结束.如要终止其作用域可使用
                #undef命令
             5.宏定义允许嵌套
                #define R 4
                #define PI 3.14
                #define AREA R*PI //嵌套定义
             6.宏名在源程序中若用 "" 括起来,则预处理程序不对其做宏代换
             7.可用宏定义表示数据类型,使书写方便
                #define INT int
                INT a;
                a=10; //相当于用宏给 int 起了一个别名
     
                #define P struct Person
                P{
                    int age;
                };
                P p1= {24};
    

    有参宏的定义方法和使用

    C语言允许宏带有参数.在宏定义中的参数称为形式参数,在宏调用中的参数称为实际参数
            对带参数的宏,在调用中,不仅要宏展开,而且要用实参去代换形参
     
            带参宏定义的一般形式为:
                
                #define 宏名(形参1,形参2...) 字符串
            带参宏调用的一般形式为:
                宏名(实参1,实参2..);
            
            例:
                #define SUM(a) a+a
     
                int result=SUM(3);
                printf("%d 
    ",result);
    

    有参宏使用的注意事项

    1.带参宏定义中,形参之间可以出现空格,但是宏名和形参表之间不能有空格出现
            2.在带参宏定义中,形式参数不分配内存单元,因此不必作类型定义.而宏调用中的实参是具体的值.要用它们去代换形参,因此必须作类型说明.这是与函数中的情况不同的.在函数中,形参和实参是两个不同的量,各有自己的作用域,调用时要把实参值赋予形参,进行"值传递"。而在带参宏中,只是符号代换,不存在值传递的问题
            3.在宏定义中的形参是标识符,而宏调用中的实参可以是表达式
            4.在宏定义中,字符串内的形参通常要用括号括起来以避免出错,在上例中的宏定义中(y)*(y)表达式的y都用括号括起来,因此结果是正确的
               例如:#define SUM(x,y) (x)*(y)+(x)+(y)
            5.宏定义也可用来定义多个语句,在宏调用时,把这些语句又代换到源程序内
                例:#define M3(m,n) m=a+2;n=a*2;
    

    应用:

     

    定义一个有参宏,求最大值
            #define MAX(a,b) a>b?a:b
    

    同样定义别名时 #define 和 typedef的区别

    宏定义只是简单地字符串代换,宏是在预处理完成的,而typedef是在编译时处理的,它不是作简单地代换,而是对类型说明符重新命名.被命名的标识符具有类型定义说明的功能
            
            例:
                #define PIN1 int* 
                typedef int *PIN2;
     
                PIN1 a,b;//这里的a 是 int* 而b是int
                PIN2 a1,b1;// 这里a1,b1 都是int* 
                
                产生差异的原因在于 一个是预处理阶段 一个是编译阶段
    

    条件编译的概念和优点:

      1.为什么要使用条件编译

    1)按不同的条件去编译不同的程序部分,因而产生不同的目标代码文件.有利于程序的移植和调试
                2)条件编译当然也可以用条件语句来实现.但是用条件语句将会对整个源程序进行编译,生产的目标代码程序很长,而采用条件编译,则根据条件只编译其中的程序段1或程序段2,生产的目标程序较短
    

     2. #if-#else条件编译指令

    格式:
                    #if 常量表达式
                        程序段1
                    #elif 常量表达式
                        程序段2
                    #else 
                        程序段3
                    #endif
     
                缺点: 判断的依据是宏定义中的数据,而不是编译器中的
    

     3 #ifdef用来半段某个宏是否定义,定义为ture

    例:
                    int a =0;
                    #ifdef DEBUG
                        a =10;
                    #else
                        a=1000;
                    #endif
    

     4. #ifndef 用来判断某个宏是否定义,没定义为true

      当使用条件编译指令调试BUG,类似于JAVA中的LOG管理

        条件:

          DEBUG1 = 1 显示调试信息

          DEBUG1 = 0 不显示调试信息

     

    #define DEBUG=1
     
            #if DEBUG1==1
            #define Log(format,...) printf(format,## __VA_ARGS__);
            #elif DEBUG1==0
            #define Log(format,...)
            #else
            #define Log(format,...)
            #endif
     
            使用
             Log("XXXXX-->",10);
     
            //format 代表形参 ...表示可变参数 也类似于java中的泛型
            //##标示可以有参数也可以没有参数 ,如果没有##就至少有一个参数
    

      

  • 相关阅读:
    线程安全和非线程安全
    spring MVC和hibernate的结合
    Spring学习笔记1——基础知识 (转)
    bitset && Luogu 3674 小清新人渣的本愿
    luogu P3452 [POI2007]BIU-Offices
    每日刷题记录
    Codeforces Round #721 (Div. 2) B2. Palindrome Game (hard version)
    2019湘潭邀请赛A
    2021CCPC浙江省赛 B
    Codeforces Round #720 (Div. 2) D
  • 原文地址:https://www.cnblogs.com/developer-wang/p/4499379.html
Copyright © 2020-2023  润新知