浅谈C/C++中可变参数的原理
上一篇 /
下一篇 2012-09-20 16:21:59
/ 个人分类:C++
可以看到,其中 va_list实际上只是一个参数指针,va_start根据你提供的最后一个固定参数来获取第一个可变参数的地址,va_arg将指针指向下一个可变参数然后返回当前值,va_end只是简单的将指针清0.u~*U,R7ZY0 用下面的代码进行测试:
q(BiV_y M B051Testing软件测试网8S g)L#|"u"c*G51Testing软件测试网"Yi;f)^O:H1}&Q3v Uf$C
- int main()
- {
- Sum(3, 10, 20, 30);
- SumStr(5, "aa", "bb", "cc", "dd", "ff");
-
- SumNew(3, 1, 2, 3);
- SumStrNew(3, "12", "34", "56");
oJ B1?j-i!d Hp0- system("pause");
- 51Testing软件测试网2R'N1n!r:dx}J
- return 0;
- }
|
51Testing软件测试网pjQ"g]0m 结果如下:51Testing软件测试网&}6|7_Sxs
51Testing软件测试网1A-^&BBy
我们上面的例子传的可变参数都是4字节的,如果我们的可变参数传的是一个结构体,结果会怎么样呢?
q
b,~KWT[
G*d0 下面的例子我们传的可变参数是std::string51Testing软件测试网8Lp#M{O6i*MX&R&y
51Testing软件测试网D$K3z6Z7_
-
- void SumStdString(int nCount, )
- {
- string str;
- va_list vl = 0;
- va_start(vl, nCount);
- 51Testing软件测试网ig4xh5D7Lc-G
- for(int i=0; i<nCount; ++i)
- {
- string p = va_arg(vl, string);
- cout << p << endl;
- str += p;
- }
uA%jV#Z0- cout << "SumStdString:" << str << endl << endl;
- }
- int main()
- {
- Sum(3, 10, 20, 30);
- SumStr(5, "aa", "bb", "cc", "dd", "ff");
- SumNew(3, 1, 2, 3);
- SumStrNew(3, "12", "34", "56");
- string s1("hello ");
- string s2("world ");
- string s3("!");
- SumStdString(3, s1, s2, s3);
- system("pause");
- return 0;
- }
d;b D;ys~5To9s%B0 运行结果如下:51Testing软件测试网F1v8CB|].g&T&S
可以看到即使传入的可变参数是std::string, 依然可以正常工作。51Testing软件测试网^6sJh?MM|9^ })z
我们可以反汇编下看看这种情况下的参数传递过程:
{5n(VH"lF Y051Testing软件测试网\!sP(t+?"s%h'kf
很多时候编译器在传递类对象时,即使是传值,也会在堆栈上通过push对象地址的方式来传递,但是上面显然没有这么做,因为它要满足可变参数的调用约定,
"IkDJBZM-_0 另外,可以看到最后在调用sumStdString后,由add esp, 58h来外部清栈。
+F"W*Qfj(f)m2F8\0 一个std::string大小是28,58h = 88 = 28 + 28 + 28 + 4.51Testing软件测试网 @'a0i#F"rwEfEC
从上面的例子我们可以看到,对于可变参数的函数,有2种东西需要确定,一是可变参数的数量,二是可变参数的类型,上
面的例子中,参数数量我们是在第一个参数指定的,参数类型我们是自己约定的。这种方式在实际使用中显然是不方便,于是我们就有了_vsprintf,我们
根据一个格式化字符串的来表示可变参数的类型和数量,比如C教程中入门就要学习printf, sprintf等。51Testing软件测试网2^tb0md](_p"m
总的来说可变参数给我们提供了很高的灵活性和方便性,但是也给会造成不确定性,降低我们程序的安全性,很多时候可变参数数量或类型不匹配,就会造成一些不容察觉的问题,只有更好的理解它背后的原理,我们才能更好的驾驭它。
7XY3b1I_@p9mW0
收藏
举报
TAG: