- 论坛徽章:
- 13
|
本帖最后由 karma303 于 2017-06-05 23:47 编辑
我之前实现可变参数的函数,像void foobar( sdf, ...),都是用很土的方式:
unsigned *parg = &sdf; (或是别的什么类型,一般都因地制宜)
然后parg[1], parg[2]...一个个来访问。 也没出过什么差错。
今天终于遭报应了,一个bug调了至少有4个小时。
简单点儿说,就是foobar的堆栈布局,不再是我想象的那样经典的C堆栈布局:
- |__sdf __|
- |_arg1__|
- |_arg2__|
- |___.____|
复制代码
是跟踪了跟踪了汇编码才发现,foobar的调用代码,还是经典的C参数入栈的方式,但进入foobar之后,gcc做了一些处理,例如把sdf复制到新的栈帧,等等。总之导致sdf下方不再是__VA_ARGS__了。导致只能用va_start/va_arg/va_end来访问。
最后把今天这段出bug的代码贴上吧(好像没必要,不过还是贴上吧)。
- void __tprobe(struct timeval *base, struct timeval *last, ...){
- long *interval, *gone;
- struct timeval now;
- gettimeofday(&now, 0);
- va_list vp;
- va_start(vp, last);
- interval = va_arg(vp, long *);
- if(interval){
- *interval = (now.tv_sec - last->tv_sec) * 1000000+
- now.tv_usec - last->tv_usec;
- gone = va_arg(vp, long *);
- if(gone){
- *gone = (now.tv_sec - base->tv_sec)*1000000+
- now.tv_usec - base->tv_usec;
- }
- }
- va_end(vp);
- *last = now;
- }
复制代码- #include<sys/time.h>
- #define TSTAMP_INIT()\
- struct timeval __tm_base;\
- struct timeval __tm_last;\
- gettimeofday(&__tm_base, 0)
- /* call like this:
- * TSTAMP() just make a timestamp. do nothing else.
- * TSTAMP(interval) make timestamp, and query interval to the latest TSTAMP()
- * TSTAMP(interval, gone) and query how many useconds had gone since TSTAMP_INIT
- *
- * The arguments @interval, @gone should be a (long *)pointer for storing result
- */
- #define TSTAMP(...)\
- __tprobe(&__tm_base, &__tm_last,##__VA_ARGS__ ,0)
复制代码
之前一直不愿意用va_arg(),一是学不会,二是是想锻炼自己多动手。现在好了,终于死心了。
|
|