- 论坛徽章:
- 0
|
va_list这样的东东究竟是怎么回事?
原来va_list就是char *啊,嘿嘿现在看看,原来是这样,以下为个人看法,
如果对了,纯属巧合
==================================
假设写了一个变参数个数的函数如下
void test(char *fmt, ...)
{
va_list myVa;
va_start(myVa, fmt);
....
}
根据楼主提供的宏扩展以后
myVa = ((char*)&fmt + (sizeof(fmt)+sizeof(int)-1)&~(sizeof(int)-1)
sizeof(int) = 2; //16机器, 0x0010 sizeof(int)-1=0x0001
sizeof(int) = 4; //32机器, 0x0000 0100
sizeof(int)-1=0x0000 0011
sizeof(int) = 8; //64机器, 0x0000 0000 0000 1000
sizeof(int)-1=0x0000 0000 0000 0111
思路:
变参数的函数, 用va_start来获得第一个变参的地址
fmt为函数调用中上一个参数在栈中的地址,
sizeof(fmt)为该参数的实际大小,
本来fmt的地址+fmt大小(也就是地址偏移应该已经可以获得下一个参数的地址了)
为什么还有sizeof(int)呢, 考虑函数调用可能有类似字节对齐的要求,
那么sizeof(int)在16,32,64位机器上分别为2,4,8
所以对sizeof(fmt)有两种情况, 一是已经符合要求, 刚好对齐
一是不符合要求, 不对齐, 那么根据要求是要多算上1,3,7个字节的
那么sizeof(fmt)+sizeof(int)-1
对第一种情况, 多加了几个字节, 是需要去掉的
对第二种情况, 加上后可能刚好满足要求, 也可能又多出了几个字节
对这两种情况都有多出的字节, 但很明显多出的字节小于1,3,7
所以看看& ~(sizeof(int)-1) 明白了吧, 把末尾几位都给去掉了
对2来说0~1是没有意义的
对4来说0~3是没有意义的
对8来说0~7是没有意义的
所以分别将sizeof(int)-1取反后再&, 将末尾的去掉
那么就大功告成了,也就是说是根据上一个参数的地址和大小取到下一个参数的地址 |
|