[C/C++標準庫]_[初級]_[如何實現std::string自己的Format(sprintf)函式]
阿新 • • 發佈:2019-02-03
場景:
1. C語言有自己的sprintf函式,但是這個函式有個缺點,就是不知道需要建立多大的buffer, 這時候可以使用snprintf函式來計算大小,只要引數 buffer為NULL, count為0即可.
2. 這裡實現std::string自己的sprintf也是用了snprintf的特性,先計算大小,再建立空間,之後存入std::string.
3. 還使用了C的可變引數特性.
std::wstring Format(const wchar_t *format,...) { va_list argptr; va_start(argptr, format); int count = _vsnwprintf(NULL,0,format,argptr); va_end(argptr); va_start(argptr, format); wchar_t* buf = (wchar_t*)malloc(count*sizeof(wchar_t)); _vsnwprintf(buf,count,format,argptr); va_end(argptr); std::wstring str(buf,count); free(buf); return str; }
讓我們看看可變引數的宣告:
typedef char * va_list;
#define _INTSIZEOF(n) ( (sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) ) #define _crt_va_start(ap,v) ( ap = (va_list)_ADDRESSOF(v) + _INTSIZEOF(v) ) #define _crt_va_arg(ap,t) ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) ) #define _crt_va_end(ap) ( ap = (va_list)0 )
注意: ap會累加,每次呼叫va_arg都會指向下一個引數,問題就是va_arg並不知道什麼時候結束,所以如果設計其他的可變引數的函式,要先傳入一個引數個數作為方法引數.
snprintf 原始碼實現是通過計算%的個數來判斷引數個數的.
參考:
If buffer is a null pointer and count is zero, len is returned as the count of characters required to format the output, not including the terminating null. To make a successful call with the same argument and locale parameters, allocate a buffer holding at least len + 1 characters.