• C语言-第16课


    第16课 - 宏定义与使用分析

     

    1. 宏定义常量

    #define定义宏常量可以出现在大地吗的任何地方。

    #define从本行开始,之后的代码都是用这个宏常量。

    例如:

    #define ERROR   -1

    #define PI       3.1415926

    #define  PATH_1    “D:DelphiCTopic3.ppt”

    #define  PATH_2     D:DelphiCTopic3.ppt

    #define  PATH_3     D:DelphiC

     

    1. 宏定义表达式

    #define表达式给有函数调用的假象,却不是函数。

    #define表达式比函数更强大。

    #define表达式比函数更容易出错。

    #define SUM(a , b) (a)+(b)

    #define MIN(a , b) ((a)<(b) ? (a) : (b))

    #define DIM(a) (sizeof(a)/sizeof(*a))

    例如:

    #include<stdio.h>

    #define MIN(a , b) ((a)<(b) ? (a) : (b))

    int main()

    {

    int i = 1;

    int j = 5;

    printf("%d ",MIN(i++,j));

    printf("%d ",i);

    }

    运行结果:

    2

    3

    分析:预编译过程中,变成printf("%d ",(i++)<(j) ? (i++) : j);一共++两次

    这里我们看到的是宏的缺点,但是他却有函数没有的功能,例如#define DIM(a) (sizeof(a)/sizeof(*a))就是函数做不到的。我们看下面的例子。

    #include <stdio.h>

    #include <malloc.h>

     

    #define MALLOC(type, x) (type*)malloc(sizeof(type)*x)

    #define FOREVER() while(1)

    #define BEGIN {

    #define END   }

    #define FOREACH(i, m) for(i=0; i<m; i++)

     

    int main()

    {

        int array[] = {1, 2, 3, 4, 5};

        int x = 0;

        int*p = MALLOC(int, 5);

        FOREACH(x, 5)

        BEGIN

            p[x] = array[x];

        END  

        FOREACH(x, 5)

        BEGIN

            printf("%d ", p[x]);

        END   

        FOREVER();  

        free(p);  

        printf("Last printf... ");  

        return 0;

    }

    运行结果:1 2 3 4 5

     

    1. 宏表达式与函数的对比

    (1) 宏表达式在预编译期被处理,编译器不知道宏表达式的存在。

    (2) 宏表达式用“实参”完全代替形象,不进行任何的运算。

    (3) 宏表达式没有任何的“调用”开销。

    (4) 宏表达式中不能出现递归的定义。

    #define FAC(n) ((n>0) ? (FAC(n-1)+1) : 0)这就是错误的。

     

    1. 宏定义的作用域限制

    #include <stdio.h>

    int f1(int a, int b)

    {

        #define _MIN_(a,b) ((a)<(b) ? a : b)    

        return _MIN_(a, b);

    }

    int f2(int a, int b, int c)

    {

        return _MIN_(_MIN_(a,b), c);

    }

    int main()

    {

        printf("%d ", f1(2, 1));

        printf("%d ", f2(5, 3, 2));  

        return 0;

    }

    运行结果:1

              2

    分析:宏定义可以出现在代码的任何地方,而且在任何其他地方都可以调用宏。这里介绍一个符号#undef。当我们使用的#define的内容,我们在后面加上这个符号,就会限制它的使用了。例如:

    int f1(int a, int b)

    {

        #define _MIN_(a,b) ((a)<(b) ? a : b)    

    return _MIN_(a, b);

    #undef

    }

    这样作用域的概念就出现了。函数里面没法定义另一个函数的,但是却可以定义另一个宏。

     

    1. 强大的内置宏

    含义

    示例

    __FILE__

    被编译的文件名

    file.c

    __LINE__

    当前的行号

    25

    __DATE__

    编译时的日期

    Jan 31 2018

    __TIME__

    编译时的时间

    17:01:01

    __STDC__

    编译器是否遵循标准C规范

    1

    定义日志,若用函数

    #include<stdio.h>

    #include<time.h>

    void f()

    {

    time_t t;

    struct tm* ti;

    time(&t);

    ti = localtime(&t);

    printf(“%s”,asctime(ti));

    printf("Enter f()... ");

    printf("Exit f()... ");

    }

    void Log(char* s)

    {

    printf("%s:%d %s ", __FILE__, __LINE__, s);

    }

    int main()

    {

    Log("Enter main()...");

    f();

    Log("Exit main()...");

    return 0;

    }

    会出现行号的错误,改为宏

    #include<stdio.h>

    #include<time.h>

     

    #define LOG(s) do{  

    time_t t;            

    struct tm* ti;         

    time(&t);            

    ti = localtime(&t);     

    printf("%s [%s:%d] %s ", asctime(ti),__FILE__, __LINE__, s);  

    }while(0)

     

    void f()

    {

    LOG("Enter f()...");

    LOG("Exit f()...");

    }

    int main()

    {

    LOG("Enter main()...");

    f();

    LOG("Exit main()...");

    return 0;

    }

    行号显示正确。注意该程序实在linux下运行的。

     

    思考:

    #define f (x) ((x)-1)注意在f后面有一个空格那么f是否带了一个参数呢?代表f(x)或者代表((x)-1),还是f代表(x) ((x)-1)呢?为什么?

    这是一个错误的用法,#define f(x) ((x)-1)这个是没问题的,但你意外发现f 后面可以加上一个空格,因为宏定义#define的用法是 #define 标识符 字符串,就是用简单的标识符取代复杂的字符串,这个字符串可以是表达式,系统认为标识符是一个函数的借口,返回表达式的值,而返回类型则与主函数中定义的x有关,也可以是一句话(要用双引号括起来,否则系统就会认为是表达式),这样就要以字符串形式输出 关键字+空格+标识符+空格+字符串,这样了在实现取代作用,如果出现多个空格,就会认为是属于字符串中的空格,但如果没有双引号,就会认为是表达式,明显这种表达式是不能运算得,于是当使用f时,就会出现一句编译错误,提示无法评估f函数返回值的类型

     

  • 相关阅读:
    CVE-2017-12149JBoss 反序列化漏洞利用
    Exp4:恶意代码分析
    Exp3:MAL_免杀原理与实践
    Exp2:后门原理与实践
    Exp1 PC平台逆向破解
    20155212 2016-2017-2《Java程序设计》课程总结
    20155117王震宇实验五网络编程与安全
    20155117王震宇实验四 Andoid开发基础实验报告
    Exp9 Web安全基础
    Exp8 web基础
  • 原文地址:https://www.cnblogs.com/free-1122/p/9720710.html
Copyright © 2020-2023  润新知