zoukankan      html  css  js  c++  java
  • 第46课

    第46课 - 函数与宏分析

    1. 函数与宏

    (1)宏是由预处理器直接替换展开的,编译器不知道宏的存在,因此参数无法进行类型检查

            函数是由编译器直接编译的实体,调用行为由编译器决定

    (2)多次使用宏会增大代码量,最终导致可执行程序的体积增大,对于嵌入式设备而言,设备资源有限,这个还是比较重要的

            函数是跳转执行的,内存中只有一份函数体存在,不存在宏的问题

    (3)宏的效率比函数高,因为宏是文本替换,没有调用开销       //  虽然宏的效率比函数稍高但副作用很大,因此,可以用函数完成的功能绝对不用宏

            函数调用会创建活动记录,效率不如宏

    (4)函数可以递归调用,但宏的定义中不能出现递归定义

    【函数与宏】

     1 #include <stdio.h>
     2 
     3 // 使用宏将一片内存区域置0
     4 #define RESET(p, len) while(len > 0) 
     5                         ((char *)p)[--len] = 0
     6 
     7 // 使用函数将一片内存区域置0
     8 void reset(void *p, int len)
     9 {
    10     while(len > 0)
    11         ((char *)p)[--len] = 0;
    12 
    13 }
    14 
    15 int main()
    16 {
    17     int a[5] = {1, 2, 3, 4, 5};
    18     int len = sizeof(a); 
    19     int i = 0;
    20 
    21     /*
    22         下面的宏和函数都可以实现置0的功能
    23         但是假如使用 RESET(10, len),这个在编译期间是不错报错的,宏不会检查参数的类型
    24         使用reset(10, len)函数在编译时就会有warning,提示传参类型不符
    25     */
    26     // reset(a, len);
    27     // RESET(a, len);
    28 
    29     for(i = 0; i < 5; i++) {
    30         printf("a[%d] = %d
    ", i, a[i]);
    31     }
    32 
    33     return 0;
    34 }

    【宏的副作用】

     1 #include <stdio.h>
     2 
     3 #define _ADD_(a, b) a + b
     4 #define _MUL_(a, b) a * b
     5 #define _MIN_(a, b) ((a) < (b) ? (a) : (b))
     6 
     7 int main()
     8 {
     9     int i = 1;
    10     int j = 10;
    11 
    12     // 预处理结果:printf("%d
    ", 1 + 2 * 3 + 4);
    13     // 预期: (1 + 2) * (3 + 4) ==> 21
    14     // 实际: 1 + 2 * 3 + 4 ==> 11
    15     printf("%d
    ", _MUL_(_ADD_(1, 2), _ADD_(3, 4)));  
    16 
    17     // 预处理结果:printf("%d
    ", ((i++) < (j) ? (i++) : (j)));
    18     // 预期: 1 < 10? 1 : 10 ==> 1
    19     // 实际: (i++) < (j) ? (i++) : (b) ==> 2
    20     printf("%d
    ", _MIN_(i++, j));  
    21                                     
    22     return 0;
    23 }

    2. 宏的妙用 

     前面讲了宏的很多副作用和缺点,那宏是不是一无是处呢?绝对不是这样的,在C语言中宏有很多妙用。

    (1)用于生成一些常规性的代码,比如下面代码中的LOG_INT、LOG_CHAR、LOG_FLOAT、LOG_POINTER

    (2)封装函数,加上类型信息,比如下面代码中的MALLOC的实现

    【宏的妙用】

     1 #include <stdio.h>
     2 #include <malloc.h>
     3 
     4 #define MALLOC(type, x)  (type*)malloc(sizeof(type) * x)
     5 #define FREE(p)          (free(p), p = NULL)
     6 
     7 #define LOG_INT(i)        printf("%s = %d
    ", #i,  i)
     8 #define LOG_CHAR(c)       printf("%s = %c
    ", #c,  c)
     9 #define LOG_FLOAT(f)      printf("%s = %f
    ", #f,  f)
    10 #define LOG_POINTER(p)    printf("%s = %p
    ", #p,  p)
    11 #define LOG_STRING(s)     printf("%s = %s
    ", #s,  s)
    12 
    13 #define FOREACH(i, n)    while(1){ int i = 0, l = n;for(i = 0; i < l; i++)    // 使用while是为了定义一个scope,局部变量都在其中
    14 #define BEGIN            {
    15 #define END              }break;}
    16 
    17 int main()
    18 {
    19     int* pi = MALLOC(int, 5);  // ①可以指定数据类型,代码可读性更强 ②返回的void *指针已经进行了强制类型转换
    20     char* str = "2020-01-14 22:38:27";
    21 
    22     LOG_STRING(str);  // str = 2020-01-14 22:38:27
    23 
    24     LOG_POINTER(pi);  // pi = 0x74f010
    25 
    26 /*
    27     while(1){ int k = 0, l = 5;for(k = 0; k < l; k++)
    28     {
    29         pi[k] = k + 1;
    30     }break;}
    31 */
    32     FOREACH(k, 5)
    33     BEGIN
    34         pi[k] = k + 1;  // 对pi对应的堆空间赋值
    35     END
    36 
    37 /*
    38     while(1){ int k = 0, l = 5; for(k = 0; k < l; k++)
    39     {
    40         int value = pi[k];
    41         printf("%s = %d
    ", "value", value);
    42     }break;}
    43 */
    44     FOREACH(k, 5)
    45     BEGIN
    46         int value = pi[k];  // 遍历pi对应的堆空间
    47         LOG_INT(value);    
    48     END
    49 
    50     FREE(pi);   // 安全的释放动态内存
    51 
    52     LOG_POINTER(pi);    // pi = nil
    53 
    54     return 0;
    55 }
  • 相关阅读:
    压缩与解压
    Ubuntu下搭建yocto
    Ubuntu 1804 进入紧急模式
    How To Configure NFS Client on CentOS 8 / RHEL 8
    Install and Configure NFS Server on RHEL 8 / CentOS 8
    结构体大小的计算
    SQL语句对数据库调优常用
    用SQL语句操作数据库高级
    windows命令行操作mysql
    创建方便的csv格式文件
  • 原文地址:https://www.cnblogs.com/shiwenjie/p/11854100.html
Copyright © 2011-2022 走看看