C 語言中提供了一些基本字符串格式化處理函數,包括:
1)puts("this is a string"); 簡單輸出字符串到 standard output 中,該函數只有多字節版本;
2)int len = printf("1 + 2 = %d", 1 + 2); 格式化輸出字符串到 standard output 中,返回值表示輸出字符串長度,其 Unicode 版本為 wprintf(const wchar_t *_Format, ...);
3)int len = sprintf(szBuffer, "1 + 2 = %d", 1 + 2); 格式化輸出字符串到 szBuffer 中,返回值表示輸出字符串長度,其中 szBuffer 定義:char szBuffer[1024];
4)當需要自己構造 printf-like 格式函數,可以借助 vsprintf 函數,具體如下:
1 int MyMessageBox (char* szCaption, char* szFormat, ...) 2 { 3 char szBuffer [1024] ; 4 va_list pArgList ; 5 6 // The va_start macro (defined in STDARG.H) is usually equivalent to: 7 // pArgList = &szFormat + sizeof (szFormat) ; 8 9 va_start (pArgList, szFormat) ; 10 11 vsprintf (szBuffer, szFormat, pArgList) ; 12 13 // The va_end macro just zeroes out pArgList for no good reason 14 va_end (pArgList) ; 15 16 return MessageBoxA (NULL, szBuffer, szCaption, 0) ; 17 }
va_list 保存了函數參數棧第一個可變參數指針,結合格式化字符串 szFormat 給出每個格式化數據類型,vsprintf 訪問每一個參數,完成格式化工作。這是可變參數函數工作原理。具體解析如下:
a. 定義 typedef char *va_list;
b. va_start (pArgList, szFormat) ;語句使 pArgList 指向第一個可變參數,szFormat 給出第一個可變參數前一個參數位置;
c. type va_arg(va_list ap, type);語句取出下一個可變參數值,其中 type 指定該可變參數類型;在以上代碼中 vsprintf 內部完成了該工作;
d. va_end (pArgList) ; 語句關閉 pArgList 指針,保持程序健壯性;
以上方法實現可變參數訪問,在函數調用中,函數參數從右到左入棧。只要直到其中任意一個參數位置,可以根據參數位置以及參數類型訪問到任意一個參數。下面構造一個簡單的可變參數訪問函數以說明其原理:
1 // agrc 表示可變參數個數,可變參數類型均為整數 2 void ArgAnalyze(int argc, ...) 3 { 4 int *ptr = &argc; 5 ++ptr; 6 for(int i = 0; i < argc; ++i) 7 { 8 std::cout<<"argv"<<i + 1<<" = "<<*ptr<<std::endl; 9 ++ptr; 10 } 11 }
5) sprintf, vsprintf 函數存在一些缺陷,當傳入 Buffer 空間小於格式化字符串空間時,函數會覆蓋鄰近區域,可能導致程序異常錯誤。因此,微軟特別定義了一些安全函數:_snprintf, _vsnprintf,通過增加傳入空間參數來避免該錯誤。同時,微軟也給出了對應的 windows 版本函數,基本與C庫版本一致。以下給出 sprintf, vsprintf 相關的安全版本, Unicode 版本以及通用版本:
ASCII Wide-Character Generic
standard version sprintf swprintf _stprintf
safe version _snprintf _snwprintf _sntprintf
windows version wsprintfA wsprintfW wsprintf
-------------------------------------------------------------------------------------
standar version vsprintf vswprintf _vstprintf
safe version _vsnprintf _vsnwprintf _vsntprintf
windows version wvsprintfA wvsprintfW wvsprintf
在 c++ 庫中,也提供了相應的字符串格式化輸出,具體如下:
1 // 輸出到 standart output(多字節版本) 2 std::cout<<"1 + 2 = "<<1 + 2<<std::endl; 3 4 // 輸出到 standart output(寬字節版本) 5 std::wcout<<L"1 + 2 = "<<1 + 2<<std::endl; 6 7 // 輸出到字符串中(多字節版本) 8 std::stringstream ss; 9 ss<<"1 + 2 = "<<1 + 2<<std::endl; 10 std::string s = ss.str(); 11 12 // 輸出到字符串中(寬字節版本) 13 std::wstringstream wss; 14 wss<<L"1 + 2 = "<<1 + 2<<std::endl; 15 std::wstring ws = wss.str();
參考資料 Programming Windows by Charles Petzold
