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

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

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

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

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

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

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

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

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

  测试结果如下: