浅谈C/C++中可变参数的原理

上一篇 / 下一篇  2012-09-20 16:21:59 / 个人分类:C++

 可以看到,其中 va_list实际上只是一个参数指针,va_start根据你提供的最后一个固定参数来获取第一个可变参数的地址,va_arg将指针指向下一个可变参数然后返回当前值,va_end只是简单的将指针清0.

'ZTa c2W |fgh.LZ0  用下面的代码进行测试

.zh A;I6Di051Testing软件测试网Ub6K1x}

51Testing软件测试网)U!C1U P1D$Br.@ ~

  1. int main()  
  2.     Sum(3, 10, 20, 30); 
  3.     SumStr(5, "aa", "bb", "cc", "dd", "ff"); 
  4.      
  5.     SumNew(3, 1, 2, 3); 
  6.     SumStrNew(3, "12", "34", "56"); 

  7. ED3~&H$K0
  8.     system("pause"); 
  9. 51Testing软件测试网&uX#[EX&C9v V$wuw
  10.     return 0; 
  11. }

l8YE _)H0  结果如下:

`(B/[!Nk W o0

51Testing软件测试网][ WaR

  我们上面的例子传的可变参数都是4字节的,如果我们的可变参数传的是一个结构体,结果会怎么样呢?51Testing软件测试网0]d:g6W9S0V&{H

  下面的例子我们传的可变参数是std::string

"KDm7X_7IeS0

5j|CUY a.{0
  1. //use va_arg,  praram is std::string 
  2. void SumStdString(int nCount, ) 
  3.     string str; 
  4.     va_list vl = 0; 
  5.     va_start(vl, nCount); 

  6. 2m,s#fS'D9z ES ZgZ0
  7.     for(int i=0; i<nCount; ++i) 
  8.     { 
  9.         string p = va_arg(vl, string); 
  10.         cout <<  p << endl; 
  11.         str += p; 
  12.     } 
  13. 51Testing软件测试网Nv8JqLQ
  14.     cout << "SumStdString:" << str << endl << endl; 
  15. int main()  
  16. Sum(3, 10, 20, 30); 
  17. SumStr(5, "aa""bb""cc""dd""ff"); 
  18. SumNew(3, 1, 2, 3); 
  19. SumStrNew(3, "12""34""56"); 
  20. string s1("hello "); 
  21. string s2("world "); 
  22. string s3("!"); 
  23. SumStdString(3, s1, s2, s3); 
  24. system("pause"); 
  25. return 0; 
  26. }

  27. 'xS^ t0W |}0 运行结果如下:

    51Testing软件测试网q6{-x1[Ia"~&Z

      可以看到即使传入的可变参数是std::string, 依然可以正常工作51Testing软件测试网;hs {$n/t u

      我们可以反汇编下看看这种情况下的参数传递过程:

    sP%Vp9_m0w0

    r4B;qw N YKX8JPn{.@0

      很多时候编译器在传递类对象时,即使是传值,也会在堆栈上通过push对象地址的方式来传递,但是上面显然没有这么做,因为它要满足可变参数的调用约定,

    ,A&zT6|azaf2t2~0

      另外,可以看到最后在调用sumStdString后,由add esp, 58h来外部清栈。

    &NWBvnn9m0

      一个std::string大小是28,58h = 88 = 28 + 28 + 28 + 4.51Testing软件测试网Gk%K CI!_'Y'j

      从上面的例子我们可以看到,对于可变参数的函数,有2种东西需要确定,一是可变参数的数量,二是可变参数的类型,上 面的例子中,参数数量我们是在第一个参数指定的,参数类型我们是自己约定的。这种方式在实际使用中显然是不方便,于是我们就有了_vsprintf,我们 根据一个格式化字符串的来表示可变参数的类型和数量,比如C教程中入门就要学习printf, sprintf等。

    !uQT(n$|_1_cz0

      总的来说可变参数给我们提供了很高的灵活性和方便性,但是也给会造成不确定性,降低我们程序的安全性,很多时候可变参数数量或类型不匹配,就会造成一些不容察觉的问题,只有更好的理解它背后的原理,我们才能更好的驾驭它。

    1F;n,y)]"B~0

TAG:

 

评分:0

我来说两句

Open Toolbar