城市直播房产教育博客汽车
快传网
汽车报价
买车新车
博客专栏
专题精品
教育留学
高考读书
房产家居
彩票视频
直播黑猫
投资微博
城市上海
政务旅游

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在使用云原生的很多微服务中,比较小规模的可能直接依靠云服务中的负载均衡器进……
高德打车再创约谈新纪录,合规问题何时才能真正解决?小米供应链金融再布局链融20亿元ABS获受理工行雄安分行破大Qorvo收购碳化硅(SiC)功率半导体制造商UnitedS尼康囗70200镜头,配置腾龙适马尼康哪家好?怎样用手机开空调用手机遥控空调的方法报告高通在智能手机WiFi芯片市场份额上升武极日报Windows11更新支持运行AndroidApp京东系腾讯系精准减持套现,常年出售韭菜的步步高收关注函OSL携手AllariaTechnology在拉美开展数字资安卓旗舰都用上16G运存了,苹果却仍然停留在4G!不卡吗?法律要求变更法国版iPhone即将不再包含EarPods耳机怎么让hdmi线穿过比它小的管子?
三年来首次跨海之旅开门红清华课程引热议,700多门课程改为全英文授课,与国际接轨gkh教学反思青春无悔(短篇)傻姑武功为什么那么高傻姑真的傻吗寒假学习计划学校校长工作计划宝宝住院期间,妈妈怎么下奶?雅虎重金布局AI赛道,CNTM快速借力上位怎么样能提升衣品?养眼的韩系穿搭更简单时髦,照着穿就可以一次难忘的班队活动小学作文热议聚热点网 王者荣耀射手篇

友情链接:中准网聚热点快百科快传网快生活快软网快好知文好找江西南阳嘉兴昆明铜陵滨州广东西昌常德梅州兰州阳江运城金华广西萍乡大理重庆诸暨泉州安庆南充武汉辽宁