字符串格式化输出

    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

posted @ 2020-03-25 15:45  罗飞居  阅读(1324)  评论(0编辑  收藏  举报