• 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中的泛型
            //##标示可以有参数也可以没有参数 ,如果没有##就至少有一个参数
    

      

  • 相关阅读:
    读书笔记——吴军《态度》
    JZYZOJ1237 教授的测试 dfs
    NOI1999 JZYZOJ1289 棋盘分割 dp 方差的数学结论
    [JZYZOJ 1288][洛谷 1005] NOIP2007 矩阵取数 dp 高精度
    POJ 3904 JZYZOJ 1202 Sky Code 莫比乌斯反演 组合数
    POJ2157 Check the difficulty of problems 概率DP
    HDU3853 LOOPS 期望DP 简单
    Codeforces 148D. Bag of mice 概率dp
    POJ3071 Football 概率DP 简单
    HDU4405 Aeroplane chess 飞行棋 期望dp 简单
  • 原文地址:https://www.cnblogs.com/developer-wang/p/4499379.html
Copyright © 2020-2023  润新知