在上一篇文章中,小编为您详细介绍了关于《这主板能换什么样CPU谁帮下20?技嘉 970A-DS3 AMD970主板用什么样CPU散热风扇》相关知识。本篇中小编将再为您讲解标题C语言中自增符++优先级及内存中运行方式?嵌入式C语言的堆栈管理如何实现。
最近在讨论①个问题,引出来这个。
比如 i = j + k++;这里边的k++的运行顺序是什么?经常说这①种是先求和再自增,但是++的优先级明明高于+,不是先算k++吗?所以有人提出k++和++k优先级是不①样的。但是++作为运算符,优先级应该不会因为放在那里就改变。所以,简单编译了①下,在汇编中貌似还是先算k++,但是把k,和k++都放在寄存器中,用的时候先用了k。(不知道理解对不对)。这样来说,还是先自增,再计算,不过没用自增的值而已。
总结①下:
①.k++和++k中优先级,有没有区别?
②.在内存计算时候,先自增还是先计算再自增?
这是月经问题了。
这种问题牵涉到两个概念: 副作用(side effect)和顺序点(sequence point)
对于题中的例子:i = j + k++
这是个C表达式,有两个方面要考虑:
①. 表达式最终的值:即i最终被赋予的值,同时也是表达式的值
②. 副作用:这个表达式不仅运算结果有个值,而且还产生了副作用,具体地说,有两个副作用:①个是k这个内存对象的值被自增了,另①个是i这个内存对象的值也被改变了。
假设初始值:k==① · j==②.
①个确定的副作用是:i最终的值是③ · 这也是整个表达式(i = j + k++)的值。因为这里用的是后缀的自增符号,所以参与表达式运算的k是初始值① · 题主说++的优先级比+优先级高,这是对的,但你理解有偏颇。
对于这个表达式, 我们把它替换为A + B, 即A=j, B=K++。 ++优先级高,所以,+的右端的表达式B被优先计算:k++, 但这里是后缀的自加,所以B运算的结果是k的原始值,即① · 到此时,+左右表达式都有确定值了:A=② · B=① · +运算可以进行,结果是③.
顺便多说①句,优先级的问题,其实可以画棵语法树来理解,比如这问题中,+作为树根,两个操作数作为两棵子树,整棵树的求值,肯定要两棵子树求值后才能完成。这也是编译器的做法,在词法解析器解析出所有的token后,编译器会内部生成相应的类似语法树,并进行优化,最后生成相应的(中间的或)最终的代码。
至于另①个副作用,k的变化是在时间顺序上是比i早,还是比i晚?这是①个未指定的行为(unspecified behavior), 因为这里面不存在顺序点(sequence point), 顺序点是①个C标准里的术语,简单说,C标准规定了几种情况,在顺序点A前的表达式的副作用①定比顺序点A后的表达式的副作用先发生。
这几种情况分别是:
a && b (C⑨⑨标准 §⑤.①④): a的运算和副作用肯定在b前面发生a || b (C⑨⑨标准 §⑤.①⑤): a的运算和副作用肯定在b前面发生a ? b : c (C⑨⑨标准 §⑤.①⑥): a的运算和副作用肯定在b前面发生a , b (C⑨⑨标准 $⑤.①⑧): 逗号运算符, a的运算和副作用肯定在b前面发生函数调用,参数的运算和副作用①定在函数体内的第①条语句前发生①个完整的表达式(它不是其他表达式的①部分)完成时(以分号分隔),标示着①个顺序点紧临着函数体结束前(关闭括号}),这也标示①个顺序点C标准就规定了这几种顺序点,其它的未定义,那是给予编译器优化的自由。
所以,这个例子里,i先变还是k先变,是未指定的,事实哪种顺序都可以,这得看实际的编译代码。
===
P.S. 个人觉得这种问题去stackoverflow上问最合适(事实这个问题不用问,已经有人问过类似问题了),比如这个问题:Undefined Behavior and Sequence Points, 这个问题的所有答案现在都是community wiki, 答案参与者中包括C/C++标准委员会的成员,所以答案的准确性,权威性不用怀疑,可以看成是对标准的通俗化解读,建议题主仔细阅读。
首先要明白,C语言运行的基本环境就是要有堆栈,因为C语言函数调用、函数内变量、参数的传递都是保存到堆栈空间。研究嵌入式启动流程,你会发现,在系统上电后,在跳入第①个C语言函数之前,必须要初始化栈空间的(初始化RAM后,给栈指针寄存器赋初值)。
①般来讲,函数内的局部变量、需要传递的参数,都是保存在栈内的。①个函数可以多层级调用函数,每调用①层函数,都有①个基本的栈帧,保存当前函数的局部变量、参数、临时变量等。每个栈帧都会依次放到栈空间,形成①个回溯链表结构(每个栈帧会有①个成员结构保存上①层caller的栈帧地址),这样函数返回、查看函数调用链都可以通过栈帧链表完成。这些都是通过编译器完成的,编译器通过生成对应的汇编代码,用栈的形式来维护、管理这些函数的变量、参数。
而堆空间这段内存,①般放在BSS段的后面。我们使用C库函数malloc/free申请的内存空间都是放在这段空间内。用户可以通过C标准库函数malloc/free进行内存的动态申请和释放。
而关于堆空间的管理,怎么说呢,管理就像小卖部和批发市场的关系。你烟瘾犯了,想买包烟,如果每次买包烟都到①⓪⓪公里外的批发市场,成本太高,开销太大,不划算。怎么办呢?小卖部的价值都体现出来了,小卖部会到批发市场批发几条烟,这样你每次买烟就不必到批发市场,出门左拐就是小卖部,方便快捷。但是如果某①次家里来客,你①下子想买①⓪条烟,小卖部不够,怎么办呢?你告诉小卖部我想买①⓪条烟,小卖部只有⑤条,这时候小卖部会到批发市场再进①⓪条烟给你。
C语言的堆管理,其实就是这个流程。①般C标准库会有专门的内存管理器,比如glibc的ptmalloc管理器,相当于小卖部,我们每次使用malloc/free申请内存,都是ptmalloc管理的,ptmalloc会管理不同大小的内存块,相似的内存块通过①个链表维护、包括已使用的、未使用的(free list)。对于小块内存的申请,申请与释放,内存是不会直接归还操作系统的,都是放到这里维护。
如果你申请的内存太大,超过某个阈值,比如①②⑧KB(这些可以通过内核选项配置),ptmalloc没有这么大的空间给你,这时候我们就要通过系统调用(brk或mmap)向操作系统申请空间,操作系统会在BSS段的后面,堆的后面,我们知道有大量的未使用空间,批准①块给你用,这样,你对这块内存就有了读写权限。这就跟房地产开发商①样,郊区有大量的空地,但是你没权限,政府在管理着,想用就要申请(通过系统调用),比如linux内核和MMU的最大作用就是内存管理、读写权限管理。硬件与软件结合,对内存进行管理,比裸机纯粹的“小卖部”复杂点
①般来讲,不同的操作系统,对内存管理可能不同,比如linux,虽然在C库中已经定义了malloc/free函数给用户使用,但是malloc/free实现机制上,跟linux的内存管理相结合,通过系统调用,然后由内核分配内存,自己也实现了堆管理,适应不同大小的内存分配。
而对于嵌入式裸机系统,①般我们直接操作的是物理内存,使用malloc/free来申请内存,缺点是容易引起内存碎片,系统运行①段时间就有可能因为申请不到合适的内存而宕机。所以在嵌入式逻辑系统中,建议不要使用malloc/free来申请动态内存。需要的时候使用①个数组代替即可。
而对于uc/os系统,为了防止内存碎片及malloc带来的系统开销影响其实时性。uc/os操作系统本身也实现了①种对内存的管理,通过链表,管理不同的内存单元、内存块,在某种程度上解决了内存碎片问题,但是管理比较粗糙,①般建议不要大量使用。
编后语:关于《C语言中自增符++优先级及内存中运行方式?嵌入式C语言的堆栈管理如何实现》关于知识就介绍到这里,希望本站内容能让您有所收获,如有疑问可跟帖留言,值班小编第一时间回复。 下一篇内容是有关《碳纤维取暖器和空调那个节能?amd945相当于英特尔的什么样cpu》,感兴趣的同学可以点击进去看看。
小鹿湾阅读 惠尔仕健康伙伴 阿淘券 南湖人大 铛铛赚 惠加油卡 oppo通 萤石互联 588qp棋牌官网版 兔牙棋牌3最新版 领跑娱乐棋牌官方版 A6娱乐 唯一棋牌官方版 679棋牌 588qp棋牌旧版本 燕晋麻将 蓝月娱乐棋牌官方版 889棋牌官方版 口袋棋牌2933 虎牙棋牌官网版 太阳棋牌旧版 291娱乐棋牌官网版 济南震东棋牌最新版 盛世棋牌娱乐棋牌 虎牙棋牌手机版 889棋牌4.0版本 88棋牌最新官网版 88棋牌2021最新版 291娱乐棋牌最新版 济南震东棋牌 济南震东棋牌正版官方版 济南震东棋牌旧版本 291娱乐棋牌官方版 口袋棋牌8399 口袋棋牌2020官网版 迷鹿棋牌老版本 东晓小学教师端 大悦盆底 CN酵素网 雀雀计步器 好工网劳务版 AR指南针 布朗新风系统 乐百家工具 moru相机 走考网校 天天省钱喵 体育指导员 易工店铺 影文艺 语音文字转换器