一、内存结构

内存大致可以分为四个部分:代码段,静态存储区,堆,栈。

具体划分如下图所示:

栈:在执行函数时,函数内部局部变量的存储单元都可以在栈上创建,函数执行结束后会自动释放内存。栈内存的分配运算内置于处理器的指令中。效率高,但分配的内存容量有限,程序发生错误时,很有可能出现栈溢出。

堆:又称为动态内存分配区,程序在执行的时候用malloc或new申请指定大小的内存,程序员自己负责在任何时候用free或delete释放内存。若在申请后未释放,在程序结束时有可能会有OS自动回收,或者造成内存泄露,因此,使用时一定要注意。

静态存储区:包括程序中明确被初始化的全局变量、静态变量、常量以及未被初始化的数据。内存在程序编译时已经分配好,这块内存在整个运行期间一直存在。

代码区:存放程序代码,代码区是可以共享的(其他的执行程序可以调用它),整个内存中只有一份。

栈和堆的区别

1.管理方式不同

栈由编译器自动管理,堆由程序员控制。

2.空间大小不同

栈是向低地址扩展的结构,是连续的内存区域,因此栈顶和栈底是规定好的,容量有限,若用户使用过多的栈空间,会产生溢出。堆是向高地址扩展,不是连续的内存区域,堆获得的空间较大,分配时也比较灵活。

3.是否产生碎片

对于堆来说,频繁的malloc/free,new/delete会是空间不连续,造成大量碎片,使得程序效率降低。而栈不存在这样的问题。

4.增长方向不同

堆和栈相对生长

5.分配方式

堆由程序员通过使用malloc、free、new、delete来进行管理。栈由编译器申请释放,栈的动态内存分配通过alloca函数完成。

6.分配效率不同

栈是机器系统提供的数据结构,计算机在底层对栈提供支持。堆是C库函数提供的,堆的效率比栈低得多。

二、函数的调用过程(栈帧)

每一次的函数调用都是一个过程,我们将这个过程称为函数的调用过程。在这个过程中,会开辟栈空间用来保存本次函数调用过程中临时变量以及现场保护等工作,这块栈空间我们称之为函数栈帧。栈帧的维护需要两个寄存器也叫帧指针,即ebp和esp,esp中存放栈顶地址,ebp存放栈底地址。esp和ebp一次只能存放一个地址。

以下是函数调用的详细过程:

如图所示,

假设函数a调用了函数b,函数b调用了函数c,函数b有三个参数,从左至右依次为参数1,参数2,参数3。

1.函数a在调用函数b的时候,首先将函数b的参数以相反的顺序依次压入栈中,即,从最后一个参数开始压栈。

2.函数a使用call指令调用函数b,并将call指令下的一条指令的地址当做返回地址压入栈中。(汇编call命令的两个功能:1.保存当前指令的下一个指令的地址。2.pc指针跳转到调用函数的入口地址。)

3.在函数b的栈帧中,首先保存函数a的栈底地址,再将函数a的栈顶地址当做函数b的栈底地址,即图中所示的push ebp和mov ebp,esp这两条指令。

4.然后,从ebp的位置开始存放函数b的局部变量,将这些变量的地址依次存放在栈中,先定义的先入栈,后定义的后入栈。

注意:在不同的编译器上函数的调用过程可能会有所不同,但大致思想相同。

三、宏和函数

(一)宏和函数的区别:

1.宏只是做简单的字符串替换,与类型无关;而函数是参数的传递,参数有类型。

2.宏参数在进行替换时是直接替换,不进行任何计算,函数在调用时会计算形参的值。

3.宏替换发生在编译之前,而函数调用发生在编译之后。

4.宏替换不占内存空间,函数在调用时有栈帧,会占用栈上的空间。

5.使用宏的执行速度更快,函数调用有跳转、现场保护、返回过程等操作,因此有额外的时间开销。

6.每次使用宏都会进行替换,因此如果有大量的宏或者宏较长,大量的宏替换会使得代码长度大幅度增加;函数只有一个,每次使用都会调用同一个地方的函数,因此代码长度较短。

7.宏不能递归,函数可以。

(二)宏的优缺点

优点:

1.提高程序的可读性,方便修改

2.避免函数入栈,出栈的操作,提高运行效率,减少系统开销

3.宏是由预处理器处理的,通过字符串的替换操作可以完成很多编译器无法实现的功能,如连接字符等

4.宏与类型无关,更通用

缺点:

1.宏不能进行调试(预处理时直接进行文本替换,不检查类型,语法等)

2.宏与类型无关,不够严谨

3.宏可能会带来运算符优先级问题

4.造成代码长度大幅度增加

5.宏不能递归,函数式宏定义会导致代码执行效率降低

(三)# 和 ## 的使用

# :用来将宏变成字符串

## :拼接宏的名字或字符串

#include #define A(a) (#a)

#define B(b,c) b##c

int main()

{

printf(A(hahaha));

//这里是将hahaha转换成字符串

printf("\n");

printf("%d",B(33,44));

//这里的33和44是两个int型数字,组合后仍是一个int型数字3344,而不是字符串

printf("\n");

printf("%s\n",B("hhhh","aaaa"));

return 0;

}

运行结果:

hahaha

3344

hhhhaaaa

C语言重要知识点总结(一)–编译链接过程、数据类型、操作符

C语言重要知识点总结(三)–const、volatile、extern、static、restrict、register关键字解析

C语言重要知识点总结(四)–结构体、结构体内存对齐、位段、枚举、联合

以上总结如有不足之处,希望指出,谢谢!

C语言编程宏定义的优缺点,C语言重要知识点总结(二)--内存结构、函数调用过程(栈帧)、宏的优缺点以及##和#的使用...相关推荐

  1. linux+下c语言编程项目,精通UNIX下C语言编程与项目实践

    cc -I  //include 目录 -L //静态库目录?动态也可以 -l //小写L,接静态库名称?动态也可以 -DXXX='"XXFF"' //-D直接定义宏 -c 只编译 ...

  2. c语言程序设计自学跟谁好,双辽c语言编程学习,双辽学c语言编程哪个好,双辽学c语言编程自学好还是报班好...

    双辽c语言编程学习,双辽学c语言编程哪个好,双辽学c语言编程自学好还是报班好 首页 > 软件 > 双辽c语言编程学习 作者:镀金池   发布时间:2017-12-07 05:48 一个C语 ...

  3. c语言程序设计需要学多久,九江c语言编程学习,九江学c语言编程报班,九江学c语言编程一般要多久才能学会...

    九江c语言编程学习,九江学c语言编程报班,九江学c语言编程一般要多久才能学会 首页 > C语言 > 九江c语言编程学习 作者:镀金池   发布时间:2017-10-18 14:11 据ID ...

  4. c语言编程学多久,丰城c语言编程学习,丰城学c语言编程的学校,丰城学c语言编程一般要多久才能学会...

    丰城c语言编程学习,丰城学c语言编程的学校,丰城学c语言编程一般要多久才能学会 首页 > 软件 > 丰城c语言编程学习 作者:镀金池   发布时间:2018-04-09 16:40 在之后 ...

  5. 成都c语言编程培训机构,成都学c语言编程,成都学c语言编程去哪里,成都学c语言编程需要报培训班吗...

    成都学c语言编程,成都学c语言编程去哪里,成都学c语言编程需要报培训班吗 首页 > 软件 > 成都学c语言编程 作者:镀金池   发布时间:2018-09-28 14:20 近似带有序布局 ...

  6. 汕头c语言培训班,汕头c语言编程学习,汕头学c语言编程哪个好,汕头学c语言编程需要报培训班吗...

    汕头c语言编程学习,汕头学c语言编程哪个好,汕头学c语言编程需要报培训班吗 首页 > C语言 > 汕头c语言编程学习 作者:镀金池   发布时间:2017-10-18 20:12 经历:若 ...

  7. 湛江C语言培训,湛江c语言编程学习,湛江学c语言编程报班,湛江学c语言编程自学好还是报班好...

    湛江c语言编程学习,湛江学c语言编程报班,湛江学c语言编程自学好还是报班好 首页 > C语言 > 湛江c语言编程学习 作者:镀金池   发布时间:2017-10-19 09:51 在Swi ...

  8. c语言宏定义_掌握C语言,中文编程不是梦

    文/Edward 前面我们在讲节程序编译的时候,编译器做的第一步就是预处理.C语言的预处理,其实是编译器在对整个工程编译之前做的一些文本性质的工作,例如我们经常使用的#include,这就是一个典型的 ...

  9. 如何用C语言改变宏定义的大小,C语言中宏定义使用的小细节

    C语言中宏定义使用的小细节 #pragma#pragma 预处理指令详解 在所有的预处理指令中,#Pragma 指令可能是最复杂的了,它的作用是设定编译器的状态或者是指示编译器完成一些特定的动作.#p ...

  10. 宏定义处理特殊字符 -_c语言编译与预处理命令

    所谓预处理,是指源文件在进行编译的第一遍扫描之前所作的工作,由预处理程序完成.当对一个源文件进行编译时,系统将自动引用预处理程序对源程序中的预处理部分进行处理,处理完毕自动进入对源程序的编译. 在前面 ...

最新文章

  1. Python逻辑运算符 and ,or not 的理解
  2. 用shell脚本计算日期的小函数们
  3. 从零开始入门 K8s | K8s 安全之访问控制
  4. 常用七大经典排序算法总结(C语言描述)
  5. 数据结构与算法 pdf_整理一个月完成的数据结构与算法PDF和测试代码免费拿
  6. Qt 给控件QLineEdit添加clicked事件方法
  7. 【script】python 使用json模块实现字符串与字典的相互转换
  8. JS收集:遍历CHECKBOX
  9. 国际认可不断增加,国产数据库发展与应用前景如何?
  10. JsonCpp 入门教程
  11. WPF MVVM框架 漂亮界面风格的WPF
  12. 塞尔之光的树心旋转机关_塞尔之光
  13. Python自学笔记11:实操案例八(咖啡馆、2019中超联赛前五,模拟手机通讯录)
  14. BigWorld用到的其他库
  15. 凭实力讲,运维工程师能不能做成预言家?
  16. 什么是top sql
  17. 如何具有更好的凝聚力,我的团队
  18. 红米ac2100有ipv6吗_Redmi路由器AC2100开箱:六天线简单直接,功能丰富对玩家友好...
  19. Vuetify中的v-pagination如何实现分页
  20. 万年历、日历——拿来即用(简单易上手,操作方便)

热门文章

  1. dnet: Failed to open device lo0
  2. go vscode go mod win环境配置
  3. IAP 与 STC 的区别
  4. 云端、小企即将到来的两头热的存储市场
  5. 二维火:智能餐饮云端互联是如何实现的?
  6. android调用系统相册将图片复制到指定目录下并显示复制进度
  7. 网络退化现象和残差网络效果
  8. Hive纵向表转横向表
  9. Flowable实战(三)流程部署管理
  10. K-hop消息传递图神经网络的表达能力有多强?