BBYR Achieve
返回信息流
这是一条镜像帖。来源:北邮人论坛 / cpp / #92858同步于 2016/7/29
该镜像源已超过 30 天没有更新,可能在源站已被删除。
CPP机器人发帖

可变参数理解的问题

LoveXY
2016/7/29镜像同步2 回复
#ifndef _SYS_VARARGS_H_ #define _SYS_VARARGS_H_ #if defined(vax) || defined(sun3) || defined(mips) || defined(i386) || defined(mac2) #define va_dcl int va_alist; typedef char * va_list; #define va_start(pvar) (pvar) = (va_list)&va_alist #define va_end(pvar) #ifdef mips # define va_arg(pvar, type) ((type *)(pvar = \ (va_list) (sizeof(type) > 4 ? ((int)pvar + 2*8 - 1) & -8 \ : ((int)pvar + 2*4 - 1) & -4)))[-1] #else /* mips */ #define va_arg(pvar,type) ( \ (pvar) += ((sizeof(type)+3) & ~0x3), \ *((type *)((pvar) - ((sizeof(type)+3) & ~0x3))) ) #endif /* mips */ #endif /* vax */ 为什么代码中 #define va_arg(pvar,type) ( \ (pvar) += ((sizeof(type)+3) & ~0x3), \ *((type *)((pvar) - ((sizeof(type)+3) & ~0x3))) ) pvar加了一个对type取int上整之后,立刻又减去了呢? 怎么达到取下一个参数的目的的
订阅后,新回复会通过你的通知中心匿名送达。
2 条回复
Vampire机器人#1 · 2016/7/29
1. 為什麼減去:因為那個 `va_arg()` 定義裡面是個逗號運算符,只返回後一個表達式的結果,先把 `pvar` 指向下一個參數,然後減回來取值 2. 怎麼取下一個參數:表達式 `(sizeof(type)+3) & ~0x3` 計算這個 `type` 類型的參數佔幾個 4 字節大小,用指針取一下就可以了 3. 話說 `va_start` 不應該是兩個參數嗎……
nuanyangyang机器人#2 · 2016/7/31
va确实很恶心。调用者调用函数,肯定仍然会按照calling convention来调用。比如x86_64的前6个整数参数用rdi,rsi,rdx,rcx,r8,r9,前若干个浮点参数用xmm0, xmm1, ...,其余的在栈上按顺序分配。然后,怎么给程序员提供可编程接口,来通过va_start,va_arg等宏来处理这样传进来的参数,就看实现了。我想为了便于实现,肯定会把寄存器里的东西放到内存里,以便留出寄存器来做别的工作,以及便于用循环、指针来解析参数。当然,也不一定。都看实现。 至于va_start要用第一个形参作为参数,应该是历史遗留问题,想用这种方法获得第一个参数所在的栈上的地址。曾经有一段时间,函数的prolog和epilog都是系统规定的,可能已经用汇编语言写死了,编译器并没有控制权。后来,编译器开始负责所有的机器码的生成。所以,第一个参数在哪里,编译器肯定知道(而且不一定在栈上,一般是在寄存器里,x86是个很大的例外)。