2012年(24)
分类: C/C++
2012-02-24 15:11:18
va_list用于定义一个变量获取可变参数指针
va_start用于将va_list定义的指针进行初始化
va_arg用于获取对应指针的真实类型数据
va_end用于清空va_list定义的指针
擒贼先擒王,在这里只解决va_arg,别的不需惧怕。曾经,我看不懂这个。看懂之后感受到了造物主的伟大。
ap+=_INTSIZEOF(t);这里就使得ap指向了下一个可变参数的起始地址。然后
ap+=_INTSIZEOF(t)-_INTSIZEOF(t)整个表达式的结果回到当前这个可变参数的起始地址,但是注意到ap已经指向下一个可变参数地址了。这就方便后续的处理 。
我们有必要了解一下C函数的调用规则了,在调用一个函数之前,调用方会将这个函数参数push(修改ESP指针),并且push规则是先push最后一个参数,最后push第一个参数,因此ESP指针最后应该是指向第一个参数。可变参数就是利用了这一点,一旦获取到第一个参数的地址后,就能够通过地址向前查找所有的参数。(注意:x86上的堆栈是反向的,push会使ESP的值减少,而不是增加)。
看到这里,相信大家应该可以编写一个简单的可变参数函数了。我还是直接copy一个,呵呵,关键时候要的就是稳健,请主宽恕我。
只有第二个是正确的,其实答案可想而知,这跟我们所写的程序有关。由于没有类型和参数的检查,最多也就只能这样了。那为什么人家的printf便可以辨识呢??那是因为函数printf是从固定参数format字符串来分析出参数的类型,再调用va_arg的来获取可变参数的。这下应该理清楚了。
可变参数宏就不说了吧,简单的画个妆而已,不过依然很强大,呵呵。
|
|
|
|
|