作者:朱金燦
國慶假期看了《程序員的自我修養——鏈接、裝載和庫》的大部分,其中P337提到了C語言變長參數的一些實現原理,書上的一個例子是(我對書上的代碼作了一些小改動,書上的例子編譯有點小問題):
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
#include <stdarg.h>
/*!
* @brief 計算n個整數之和,這個暫時沒有計算結果越界的問題
*
* @param [in]num 要計算的整數個數
* @return 計算結果
*/
long sum(int num,...)
{
assert(num>0);
int *p = &num+1;
long ret = 0;
while (num--)
{
ret +=*p++;
}
return ret;
}
這裡利用了函數的棧上的位置依次排列的原理(即不定參數的地址依次在變量num的高地址方向,同時函數調用約定采用的是cdecl)。下面是我參考MSDN實現和C語言的printf函數一樣功能的MyPrintf函數:
/*!
* @brief 格式化字符串輸出到控制台
*
* @param [in]pFormat 格式化字符串
* @return 無
*/
void MyPrintf(TCHAR* pFormat, ... )
{
va_list pArg;
va_start(pArg, pFormat);
int len;
TCHAR* buffer;
len = _vsctprintf(pFormat,pArg )+ 1; // _vscprintf doesnt count, terminating
buffer = (TCHAR*)(malloc(len * sizeof(TCHAR)));
_vstprintf_s(buffer, len, pFormat,pArg);
_putts( buffer );
free( buffer );
va_end(pArg);
}
上面兩個函數的測試代碼:
int _tmain(int argc, _TCHAR* argv[])
{
int x = 10;
int y = 110;
int z =200;
long Ret = sum(3,x,y,z);
MyPrintf(_T("%d %c %d"),123,<,456 );
MyPrintf(_T("%s"),_T("This is a string"));
getchar();
return 0;
}
測試環境:Win XP + sp3, VS 2008 + sp1,unicode字符集。
參考文獻:
1. 《程序員的自我修養--鏈接、裝載和庫》,俞甲子 / 石凡 / 潘愛民
2. MSDN(與VS 2008 + sp1配套)