免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 1893 | 回复: 2

[其他] 还是乖乖的用va_arg()吧 [复制链接]

论坛徽章:
13
程序设计版块每日发帖之星
日期:2016-06-29 06:20:00每日论坛发贴之星
日期:2016-08-14 06:20:00操作系统版块每日发帖之星
日期:2016-08-14 06:20:00每日论坛发贴之星
日期:2016-08-13 06:20:00数据库技术版块每日发帖之星
日期:2016-08-13 06:20:00程序设计版块每日发帖之星
日期:2016-08-13 06:20:00IT运维版块每日发帖之星
日期:2016-08-13 06:20:00每日论坛发贴之星
日期:2016-08-12 06:20:00数据库技术版块每日发帖之星
日期:2016-08-12 06:20:00程序设计版块每日发帖之星
日期:2016-08-12 06:20:00操作系统版块每日发帖之星
日期:2016-08-12 06:20:00综合交流区版块每日发帖之星
日期:2016-08-09 06:20:00
发表于 2017-06-05 23:43 |显示全部楼层
本帖最后由 karma303 于 2017-06-05 23:47 编辑

我之前实现可变参数的函数,像void foobar( sdf, ...),都是用很土的方式:
unsigned *parg = &sdf; (或是别的什么类型,一般都因地制宜)
然后parg[1], parg[2]...一个个来访问。 也没出过什么差错。
今天终于遭报应了,一个bug调了至少有4个小时。

简单点儿说,就是foobar的堆栈布局,不再是我想象的那样经典的C堆栈布局:
  1. |__sdf __|
  2. |_arg1__|
  3. |_arg2__|
  4. |___.____|
复制代码


是跟踪了跟踪了汇编码才发现,foobar的调用代码,还是经典的C参数入栈的方式,但进入foobar之后,gcc做了一些处理,例如把sdf复制到新的栈帧,等等。总之导致sdf下方不再是__VA_ARGS__了。导致只能用va_start/va_arg/va_end来访问。

最后把今天这段出bug的代码贴上吧(好像没必要,不过还是贴上吧)。
  1. void __tprobe(struct timeval *base, struct timeval *last,  ...){
  2.     long *interval, *gone;
  3.     struct timeval now;
  4.     gettimeofday(&now, 0);

  5.     va_list vp;
  6.     va_start(vp, last);
  7.     interval = va_arg(vp, long *);
  8.     if(interval){
  9.         *interval = (now.tv_sec - last->tv_sec) * 1000000+
  10.                             now.tv_usec - last->tv_usec;
  11.         gone = va_arg(vp, long *);
  12.         if(gone){
  13.             *gone = (now.tv_sec - base->tv_sec)*1000000+
  14.                             now.tv_usec - base->tv_usec;
  15.         }
  16.     }
  17.     va_end(vp);
  18.     *last = now;
  19. }
复制代码
  1. #include<sys/time.h>
  2. #define TSTAMP_INIT()\
  3.     struct timeval __tm_base;\
  4.     struct timeval __tm_last;\
  5.     gettimeofday(&__tm_base, 0)

  6. /* call like this:
  7. * TSTAMP()                just make a timestamp. do nothing else.
  8. * TSTAMP(interval)        make timestamp, and query interval to the latest TSTAMP()
  9. * TSTAMP(interval, gone)    and query how many useconds had gone since TSTAMP_INIT
  10. *
  11. * The arguments @interval, @gone should be a (long *)pointer for storing result
  12. */
  13. #define TSTAMP(...)\
  14.     __tprobe(&__tm_base, &__tm_last,##__VA_ARGS__ ,0)

复制代码

之前一直不愿意用va_arg(),一是学不会,二是是想锻炼自己多动手。现在好了,终于死心了。

论坛徽章:
11
摩羯座
日期:2013-09-29 17:39:09白羊座
日期:2014-11-13 09:38:14技术图书徽章
日期:2014-01-17 15:07:36狮子座
日期:2013-12-25 14:01:52技术图书徽章
日期:2013-12-17 11:33:22技术图书徽章
日期:2013-12-03 10:27:57天秤座
日期:2013-11-08 15:47:19申猴
日期:2013-10-29 13:16:32未羊
日期:2013-10-12 22:28:56辰龙
日期:2013-10-09 14:39:5515-16赛季CBA联赛之山东
日期:2016-07-25 10:23:00
发表于 2017-06-08 12:55 |显示全部楼层
楼主很给力哈

论坛徽章:
7
IT运维版块每日发帖之星
日期:2016-05-27 06:20:00IT运维版块每日发帖之星
日期:2016-06-09 06:20:00操作系统版块每日发帖之星
日期:2016-06-12 06:20:00程序设计版块每日发帖之星
日期:2016-06-12 06:20:00操作系统版块每日发帖之星
日期:2016-06-13 06:20:00IT运维版块每日发帖之星
日期:2016-06-17 06:20:002015-2016NBA季后赛纪念章
日期:2016-06-28 17:42:27
发表于 2017-06-13 11:40 |显示全部楼层
出错的代码呢? 帖的是正确的吧
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP