要理解可变参数,首先要理解函数调用约定, 为什么只有__cdecl的调用约定支持可变参数,而__stdcall不支持?

  实际上__cdecl和__stdcall函数参数都是从右到左入栈,它们的区别在于由谁来清栈,__cdecl由外部调用函数清栈,而__stdcall由被调用函数本身清栈, 显然对于可变参数的函数,函数本身没法知道外部函数调用它时传了多少参数,所以没法支持被调用函数本身清栈(__stdcall), 所以可变参数只能用__cdecll。

  另外还要理解函数参数传递过程中堆栈是如何生长和变化的,从堆栈低地址到高地址,依次存储 被调用函数局部变量,上一函数堆栈桢基址,函数返回地址,参数1, 参数2, 参数3....

  有了上面的知识,我可以知道函数调用时,参数2的地址是参数1的地址加上参数1的长度,而参数3的地址是参数2的地址加上参数2的长度,以此类推。

  于是我们可以自己写可变参数的函数了, 代码如下:

  1. int Sum(int nCount, ) 
  2. { 
  3.     int nSum = 0; 
  4.     int* p = &nCount; 
  5.     for(int i=0; i<nCount; ++i) 
  6.     { 
  7.         cout << *(++p) << endl; 
  8.         nSum += *p; 
  9.     } 
  10.  
  11.     cout << "Sum:" << nSum << endl << endl; 
  12.     return nSum; 
  13. } 
  14.  
  15. string  SumStr(int nCount, ) 
  16. { 
  17.     string str; 
  18.     int* p = &nCount; 
  19.  
  20.     for(int i=0; i<nCount; ++i) 
  21.     { 
  22.         char* pTemp = (char*)*(++p); 
  23.         cout <<  pTemp << endl; 
  24.         str += pTemp; 
  25.     } 
  26.  
  27.     cout << "SumStr:" << str << endl; 
  28.     return str; 
  29. }

  在我们的测试函数中nCount表示后面可变参数的个数,int Sum(int nCount,...)会打印后面的可变参数Int值,并且进行累加;string  SumStr(int nCount,...) 会打印后面可变参数字符串内容,并连接所有字符串。

  然后用下面代码进行测试:int main()

  1. { 
  2.     Sum(3, 10, 20, 30); 
  3.     SumStr(5, "aa", "bb", "cc", "dd", "ff"); 
  4.      
  5.     system("pause"); 
  6.  
  7.     return 0; 
  8. }

  测试结果如下: