iis服务器助手广告广告
返回顶部
首页 > 资讯 > 后端开发 > 其他教程 >C语言深入分析函数与宏的使用
  • 855
分享到

C语言深入分析函数与宏的使用

2024-04-02 19:04:59 855人浏览 泡泡鱼
摘要

目录一、函数与宏二、宏的妙用三、小结一、函数与宏 宏是由预处理器直接替换展开的,编译器不知道宏的存在函数是由编译器直接编译的实体,调用行为由编译器决定多次使用宏会导致最终可执行程序的

一、函数与宏

  • 宏是由预处理器直接替换展开的,编译器不知道宏的存在
  • 函数是由编译器直接编译的实体,调用行为由编译器决定
  • 多次使用宏会导致最终可执行程序的体积增大
  • 函数是跳转执行的,内存中只有一份函数体存在
  • 宏的效率比函数要高,因为是直接展开,无调用开销
  • 函数调用时会创建活动记录,效率不如宏

下面看一个函数与宏的示例,先看这个程序:

#include <stdio.h>
 
#define RESET(p, len)          \
    while( len > 0 )           \
        ((char*)p)[--len] = 0
 
void reset(void* p, int len)
{
    while( len > 0 ) 
        ((char*)p)[--len] = 0;
}
 
int main()
{
    int array[] = {1, 2, 3, 4, 5};
    int len = sizeof(array);
    int i = 0;
    
    RESET(array, len);
    
    for(i=0; i<5; i++)
    {
        printf("array[%d] = %d\n", i, array[i]);
    }
    
    return 0;
}

输出结果如下:

但是如果我们这么写,RESET(6, len); 程序直接出现段错误,都没有给出警告:

而我们使用函数 reset(6, len); 时,则会出现警告:

所以说能用函数实现的功能就尽可能的不使用宏。 

  • 宏的效率比函数稍高,但是其副作用巨大
  • 宏是文本替换,参数无法进行类型检查
  • 可以用函数完成的功能绝对不用宏
  • 宏的定义中不能出现递归定义 

下面看一个宏的副作用的代码:

#include <stdio.h>
 
#define _ADD_(a, b) a + b
#define _MUL_(a, b) a * b
#define _MIN_(a, b) ((a) < (b) ? (a) : (b))
 
int main()
{
    int i = 1;
    int j = 10;
    
    printf("%d\n", _MUL_(_ADD_(1, 2), _ADD_(3, 4)));
    printf("%d\n", _MIN_(i++, j));
    
    return 0;
}

输出结果如下:

按理说输出结果应该是 21 和 1 ,为什么是 11 和 2 呢?下面进行单步调试,输入  GCc -E test.c -o test.i ,得到 test.i 文件,部分结果如下:

这样就能解释了。

二、宏的妙用

  • 用于生成一些常规性的代码
  • 封装函数,加上类型信息

下面看一个宏的妙用的示例:

#include <stdio.h>
#include <malloc.h>
 
#define MALLOC(type, x)   (type*)malloc(sizeof(type)*x)
#define FREE(p)           (free(p), p=NULL)
 
#define LOG_INT(i)        printf("%s = %d\n", #i, i)
#define LOG_CHAR(c)       printf("%s = %c\n", #c, c)
#define LOG_FLOAT(f)      printf("%s = %f\n", #f, f)
#define LOG_POINTER(p)    printf("%s = %p\n", #p, p)
#define LOG_STRING(s)     printf("%s = %s\n", #s, s)
 
#define FOREACH(i, n)     while(1) { int i = 0, l = n; for(i=0; i < l; i++)
#define BEGIN             {
#define END               } break; } 
 
int main()
{
    int* pi = MALLOC(int, 5);
    char* str = "AutumnZe";
    
    LOG_STRING(str);
    
    LOG_POINTER(pi);
    
    FOREACH(k, 5)
    BEGIN
        pi[k] = k + 1;
    END
    
    FOREACH(n, 5)
    BEGIN
        int value = pi[n];
        LOG_INT(value);
    END
    
    FREE(pi);
    
    LOG_POINTER(pi);
    
    return 0;
}

输出结果如下:

输入  gcc -E test.c -o test.i ,看看中间文件 test.i,就能理解这段宏的巧妙之处。

int main()
{
    int* pi = (int*)malloc(sizeof(int)*5);
    char* str = "AutumnZe";
 
    printf("%s = %s\n", "str", str);
 
    printf("%s = %p\n", "pi", pi);
 
    while(1) { int k = 0, l = 5; for(k=0; k < l; k++)
    {
        pi[k] = k + 1;
    } break; }
 
    while(1) { int n = 0, l = 5; for(n=0; n < l; n++)
    {
        int value = pi[n];
        printf("%s = %d\n", "value", value);
    } break; }
 
    (free(pi), pi=((void *)0));
 
    printf("%s = %p\n", "pi", pi);
 
    return 0;
}

三、小结

  • 宏和函数并不是竞争对手
  • 宏能够接受任何类型的参数,效率高,易出错
  • 函数的参数必须是固定类型,效率稍低,不易出错
  • 宏可以实现函数不能实现的功能

到此这篇关于C语言深入分析函数与宏的使用的文章就介绍到这了,更多相关C语言 函数与宏内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

--结束END--

本文标题: C语言深入分析函数与宏的使用

本文链接: https://www.lsjlt.com/news/146206.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • C语言深入分析函数与宏的使用
    目录一、函数与宏二、宏的妙用三、小结一、函数与宏 宏是由预处理器直接替换展开的,编译器不知道宏的存在函数是由编译器直接编译的实体,调用行为由编译器决定多次使用宏会导致最终可执行程序的...
    99+
    2022-11-13
  • C语言函数与宏怎么使用
    这篇文章主要讲解了“C语言函数与宏怎么使用”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“C语言函数与宏怎么使用”吧!一、函数与宏宏是由预处理器直接替换展开的,编译器不知道宏的存在函数是由编译...
    99+
    2023-06-30
  • C语言深入讲解宏的定义与使用方法
    目录一、C语言中的宏定义二、宏定义表达式三、宏表达式与函数的对比四、有趣的问题五、强大的内置宏六、小结一、C语言中的宏定义 #define是预处理器处理的单元实体之一#define ...
    99+
    2022-11-13
  • C语言深入浅出分析函数指针
    我们先看一个代码: #include<stdio.h> void test() { printf("haha\n"); } int main() { printf("...
    99+
    2022-11-13
  • C语言深入分析递归函数的实现
    目录一、递归的数学思想二、递归函数三、递归函数设计技巧四、递归函数设计示例一五、递归函数设计示例二六、递归函数设计示例三七、小结一、递归的数学思想 递归是一种数学上分而自治的思想 递...
    99+
    2022-11-13
  • C语言深入讲解函数的使用
    目录关于函数1. 函数的定义形式2. 函数的声明3. 返回语句4. 函数参数4.1 形式参数(传值调用)4.2 实际参数(传址调用)4.3 无参数5. 函数的调用5.1 嵌套调用5....
    99+
    2022-11-13
  • C语言详细分析宏定义的使用
    目录一、C语言中函数的“缺陷”二、再次理解函数三、C语言中的宏四、宏与函数的不同五、编译器组成简介六、宏使用示例七、再论宏常量八、小结一、C语言中函数的&ld...
    99+
    2022-11-13
  • C语言深入讲解函数参数的使用
    目录一、函数参数二、程序的顺序点三、小结-上四、调用约定五、可变参数六、可变参数的限制七、小结-下一、函数参数 函数参数在本质上与局部变量相同在栈上分配空间函数参数的初始值是函数调用...
    99+
    2022-11-13
  • C++深入分析内联函数的使用
    目录一、常量与宏回顾二、内联函数三、内联函数使用注意事项四、小结一、常量与宏回顾 C++中的const常量可以替代宏常数定义,如︰ 但是C++中是否有解决方替代宏代码片段呢?这里就...
    99+
    2022-11-13
  • C语言宏函数container of()怎么使用
    本篇内容主要讲解“C语言宏函数container of()怎么使用”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“C语言宏函数container of()怎么使用”吧!在lin...
    99+
    2023-06-22
  • 深入浅析C语言与C++的区别与联系
    目录一、C语言是面向过程语言,而C++是面向对象语言1、面向过程和面向对象的区别2、面向过程和面向对象的优缺点面向过程语言面向对象语言二、具体语言上的区别1、关键字的不同2、后缀名不...
    99+
    2022-11-12
  • C语言中的内联函数(inline)与宏定义(#define)详细解析
    先简明扼要,说下关键:1、内联函数在可读性方面与函数是相同的,而在编译时是将函数直接嵌入调用程序的主体,省去了调用/返回指令,这样在运行时速度更快。2、内联函数可以调试,而宏定义是不...
    99+
    2022-11-15
    内联函数 宏定义
  • C语言深入讲解动态内存分配函数的使用
    目录一、malloc二、free(用于释放动态开辟的空间)三、calloc四、realloc五、常见的动态内存分配错误六、柔性数组局部变量和函数的形参向栈区申请空间 全局变量和sta...
    99+
    2022-11-13
  • C语言函数使用实例分析
    这篇文章主要介绍了C语言函数使用实例分析的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇C语言函数使用实例分析文章都会有所收获,下面我们一起来看看吧。函数的声明和定义函数声明告诉编译器有一个函数叫什么,参数是什么...
    99+
    2023-06-30
  • c语言深入理解函数的递归
    前言:  首先,递归是什么,递归就是在定义函数时,然后在函数里调用这个函数,通俗讲,就是函数自己调用自己。那么递归的好处是什么呢?它能够将复杂的问题,用少量的代码来表示,增加了代码的...
    99+
    2022-11-13
  • C语言深入探究函数的溯源
    目录一、函数的由来二、模块化程序设计三、C 语言中的模块化四、面向过程的程序设计五、声名和定义六、小结一、函数的由来 二、模块化程序设计 三、C 语言中的模块化 四、面向过程的...
    99+
    2022-11-13
  • C语言深入详解四大内存函数的使用
    目录1.memcpy2.memmove3.memcmp4.memset1.memcpy 与字符串函数 strcpy 类似,也是进行拷贝。但是需要注意的是,strcpy 是针对字符串进...
    99+
    2022-11-13
  • C语言详细分析宏定义与预处理命令的应用
    目录宏定义与预处理命令预处理命令 - 宏定义定义符号常量定义傻瓜表达式定义代码段预定义的宏函数 VS 宏定义预处理命令 - 条件式编译示例宏定义与预处理命令 预处理阶段:处理宏定义与...
    99+
    2022-11-13
  • 深入分析C语言存储类型与用户空间内部分布
    目录1、定义变量的格式2、6个存储类型3、auto存储类型-自动存储类型4、register存储类型-寄存器存储类型5、const存储类型-常量存储类型6、static-静态存储类型...
    99+
    2022-12-26
    C语言存储类型 C语言用户空间内部分布
  • C++深入分析讲解函数与重载知识点
    目录函数的默认(缺省)参数1、默认参数的定义2、默认参数的注意点占位参数1、占位参数 函数内部无法使用2、占位参数 可以设置成缺省参数函数重载函数的默认(缺省)参数 1、默认参数的定...
    99+
    2022-11-13
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作