安庆大理运城常德铜陵江西
投稿投诉
江西南阳
嘉兴昆明
铜陵滨州
广东西昌
常德梅州
兰州阳江
运城金华
广西萍乡
大理重庆
诸暨泉州
安庆南充
武汉辽宁

C深入理解变长参数列表的底层原理(核心是构造的四个宏)

3月3日 喵小咪投稿
  先看一个按语法规则编写的使用变长参数列表的实例:Usingvariablelengthargumentlists。doubleaverage(int,。。。);intmain(){doubledouble137。5;doubledouble222。5;doubledouble31。7;doubledouble410。2;coutfixedsetprecision(1)double1double1double2double2double3double3double4double4endlsetprecision(3)Theaverageofdouble1anddouble2isaverage(2,double1,double2)Theaverageofdouble1,double2,anddouble3isaverage(3,double1,double2,double3)Theaverageofdouble1,double2,double3anddouble4isaverage(4,double1,double2,double3,double4)getchar();return0;}calculateaveragedoubleaverage(intcount,。。。){doubletotal0;实质是定义了一个指针类型,后续通过这个指针的算术运算(指针移动)去指向每一个参数vastart(list,count);使用list指向第一个参数processvariablelengthargumentlistfor(inti1;i)totalvaarg(list,double);list按double长度移动,使用一次即移动一个double类型长度vaend(list);list置NULL}output:double137。5double222。5double31。7double410。2Theaverageofdouble1anddouble2is30。000Theaverageofdouble1,double2,anddouble3is20。567Theaverageofdouble1,double2,double3anddouble4is17。975
  不考虑一般化的情况,针对特定情况按上面的注释改写一下函数(没有使用stdarg。h头文件提供的宏,也就是针对情况情况找到每一个参数的地址,并通过指针的算术运算(移动),逐个找到其它参数):Usingvariablelengthargumentlists。doubleaverage(int,。。。);intmain(){doubledouble137。5;doubledouble222。5;doubledouble31。7;doubledouble410。2;coutfixedsetprecision(1)double1double1double2double2double3double3double4double4endlsetprecision(3)Theaverageofdouble1anddouble2isaverage(2,double1,double2)Theaverageofdouble1,double2,anddouble3isaverage(3,double1,double2,double3)Theaverageofdouble1,double2,double3anddouble4isaverage(4,double1,double2,double3,double4)getchar();return0;}calculateaveragedoubleaverage(intcount,。。。){doubletotal0;实质是定义了一个指针类型,后续通过这个指针的算术运算(指针移动)去指向每一个参数vastart(list,count);使用list指向第一个参数list(char)countsizeof(int);要考虑栈指针对齐的问题processvariablelengthargumentlistfor(inti1;i){vaarg(list,double);list按double长度移动,使用一次即移动一个double类型长度total((double)list);listsizeof(double);}vaend(list);list置NULLlistNULL;}output:double137。5double222。5double31。7double410。2Theaverageofdouble1anddouble2is30。000Theaverageofdouble1,double2,anddouble3is20。567Theaverageofdouble1,double2,double3anddouble4is17。975
  上面考虑的是具体情况,C标准库肯定要写成一般化的形式,同时还要考虑到栈对齐的情况,以及其它各种参数类型的形式。
  我们可以看到stdarg。h中对4个宏的定义:defineINTSIZEOF(n)((sizeof(n)sizeof(int)1)(sizeof(int)1))definevastart(ap,v)(ap(valist)vINTSIZEOF(v))definevaarg(ap,t)((t)((apINTSIZEOF(t))INTSIZEOF(t)))definevaend(ap)(ap(valist)0)
  需要的前置知识:
  I栈对齐,一般是按字长对齐,通常一个字长的字节数等于sizeof(int),不同的平台有不同的字长,如16位系统的字长就是2个字节,sizeof(int)等于2。32位系统的字长就是4个字节,sizeof(int)等于4。54位系统的字长就是8个字节,sizeof(int)等于8。
  II指针加减一个整型值(如n)的算术运算,表示指针的移动或偏移,其移动的步长是指针目标类型的长度。如:其步长为sizeof(char);其步长为sizeof(int);其步长为sizeof(double);
  
  使用char指针类型,便于指针类型转换时各个指针类型长度偏移的计算,因为char的长度为一个字节。第1个宏
  defineINTSIZEOF(n)((sizeof(n)sizeof(int)1)(sizeof(int)1))
  通过位运算实现栈按字长(int长度)对齐。includestdio。hintalignFloor(intn,intm){returnn(m1);位运算同等实现,2xm,x为正整数}intalignCelling(intn,intm)栈对齐要向上舍入{if0if(nm)return(nm)elsereturn(nm1)return(nm1)(m1);位运算同等实现,2xm,x为正整数endif}intmain(){intarr〔〕{1,2,3,4,5,6,7,8},m4;for(inti0;i8;i)printf(ddd,arr〔i〕,alignFloor(arr〔i〕,m),alignCelling(arr〔i〕,m));getchar();return0;}104204304444548648748888
  2xm,x为正整数
  m1如果用二进制表示,表示低位有x个1,其它高位都是0。
  (m1)如果用二进制表示,表示低位有x个0,其它高位都是0。
  当某个数与(m1)做位运算,x个低位都会置‘0’。
  例如使用的是32位平台,sizeof(int)1)等于3,其二进制编码为:
  0000000000000000000000000011
  sizeof(int)1)等于4,其二进制编码为:
  1111111111111111111111111100
  当某一个数与sizeof(int)1)进行与运算()时,其最后两位如果是1会被置0,如果本身是0则不变,而低位的第3位的位置是4,对应sizeof(int)的值。第2个宏
  definevastart(ap,v)(ap(valist)vINTSIZEOF(v))
  char类型的指针ap指向变长参数列表前的参数v的下一个参数。
  这里的v表示变长参数列表前的参数名,先取值,然后做类型转换,转换为char类型,其移动步长为1个字节,再加上v的字节数(宏考虑了栈字节对齐)。第3个宏
  definevaarg(ap,t)((t)((apINTSIZEOF(t))INTSIZEOF(t)))
  指针ap转换为t类型,并将ap偏移(向前移动)一个步长(sizeof(t),对转换后的ap做解引用。
  ap加减同一个数并不是多此一举,虽然整体表达式计算的地址没有发生改变,但ap却产生了副作用(运算符),ap指向了下一个参数。
  通常我们使用后置来下移一个数组元素:voidtest1(){doublearr〔〕{1,2,3,4,5,6};for(inti0;i)printf(。2f,p);后置可以实现指针后移一个元素}
  但如果是用char指针指向double数组,无法使用后置操作,但可以变通一下:voidtest2(){doublearr〔〕{1,2,3,4,5,6};charq(char)for(intj0;j)printf(。2f,((double)((qsizeof(double))sizeof(double))));}第4个宏
  definevaend(ap)(ap(valist)0)
  将指针ap置NULL。
  ref:
  https:www。douban。comnote707270642?i5521538AHiJZV,5534889AHiJZV
  https:www。toutiao。comi6857664589912343052
  End
投诉 评论 转载

麦岩智能完成两轮融资加速智能服务机器人研发近日,智能服务机器人公司麦岩智能宣布完成近亿元的天使轮及PreA轮融资。本轮融资由耀途资本等领投,元禾原点、界石投资、雅瑞资本、ScalePartners势乘资本跟投,Scal……糖尿病人可以不可以吃南瓜?南瓜,对于我们来说是美味的食物,可是对于它的功效,确是众说纷纭,有人说它降糖,有人说它升糖,对于大多数糖友来说,南瓜降血糖的观点是广为流传,早就根深蒂固了,甚至很多……2018款MacBookPro已经发布,2017款还值得入手感谢邀请。ICE机智(icejizhi):知道你想知道的数码知识。小编认为:17款MacBookPro值得购买!昨日,苹果在官网悄然更新了全新的2018款MacBo……小鹏P7NGP自动导航辅助驾驶公测版将开放【2021年1月22日】昨日晚间,小鹏汽车正式开启P7车型新一轮OTA升级的小范围公测,XmartOS对应版本号为2。5。0,本次OTA升级是小鹏汽车史上推送功能最多、最大的一……华为发布5年前文章,任正非亲自审签,5年过去的难题仍存有近日,华为在心声社区发布了一篇5年前的文章内容华为到该摧毁产品研发金字塔式的情况下了,由任正非亲自审签。原文中指出了华为产品研发管理体系存在的不足,包含高效率低下、权威专家工作……赛达科技人脸无感考勤,让人员管理更简单进入科技加速发展的人工智能时代,智慧化的楼宇逐渐流行,而通行作为日常工作绕不开的主题,也通过融入AI带来极致流畅的通行体验。近年来,人脸无感考勤逐步进入人们视野,仅需走近……36氪独家京东AI发起人技术委员会主席周伯文离职,将于AI方文邓咏仪、苏建勋编辑杨轩36氪从多个独立信源处获悉,京东技术委员会主席周伯文已正式从京东离职,将于AI方向创业。在京东内部系统,周伯文所在的岗位仍显示为管理者……听说贵阳老城区房价要上涨到25000元一平米,你能接受吗?房价跌涨,都只是市场规律。但随着时间的推移,物价的涨幅,贵阳房价标到25000每平,也正常。真正看的,不应是表面价格,而是含金量。实际上,贵阳现在房价含金量,比三十年前低……苹果A15继续挤牙膏,却嘲讽安卓旗舰不如老掉牙的A13苹果正式发布了新款手机iPhone13,不过其搭载的A15处理器性能仅比上一代的A14提升一成多,因此业界人士嘲讽苹果在挤牙膏,而苹果高管则反讽当下安卓旗舰处理器性能还不如两年……2021全球十大工程成就发布中国天眼FAST等入选来源:人民网原创稿人民网北京12月16日电(记者赵竹青)工程造福人类,科技创造未来。过去几年,哪些重大工程科学和技术深刻影响我们的生活?近日,由中国工程院院刊《Engin……C深入理解变长参数列表的底层原理(核心是构造的四个宏)先看一个按语法规则编写的使用变长参数列表的实例:Usingvariablelengthargumentlists。includeiostreamincludeiomanipin……SpringCloud升级之路2020。0。x版29。SCO本系列代码地址:https:github。comJoJoTecspringcloudparent在使用云原生的很多微服务中,比较小规模的可能直接依靠云服务中的负载均衡器进……
有哪些精简实用的app可以推荐?云南支撑重点产业迈向中高端到2025年力争突破关键核心技术4干货电脑系统如何安装,十分钟学会它想成为宿舍之星?大一新生购机指南此消彼长,十年间23。6万员工选择了中国移动什么手机实用?聊一款性能提升明显的品牌台式机雷神911黑武士4简看紫光股份获省级工程技术研究中心认定,思必驰科研创新加速度三星手机烧屏是不是100会发生?笛笛叫船智慧水上物流平台,打造内河货运市场正向良性循环新能源汽车基础配套项目寻找投资人,好机会和大趋势不是每年都有

友情链接:中准网聚热点快百科快传网快生活快软网快好知文好找七猫云易事利