作者:zyl910
一、缘由
在写一些生成文本的程序时,经常需要使用带缩进的格式化输出的功能。以前为此写过不少类似的函数,可惜它们的可重用性很差。
这是因为——
1) C语言的FILE*不支持重定向到自己的缓冲区。
2) C++的流机制允许重定向到自己的流缓冲区。可惜这依赖了C++的专有语法,纯C无法用上。
因为上述原因,以前至少得为C与C++编写两套函数集。如果考虑到char/wchat_t/TCHAR,函数集会变得更加臃肿。
于是我决定编写一套“能以相同的代码绑定到 C FILE 或 C++流”的带缩进的格式化输出库。zltabout就是该想法的成果。
二、C范例
Step 1 定义 ZLTABOUTMODE 宏 与 引入 zltabout.h:
#define ZLTABOUTMODE 1 // ZLTABOUTMODE_C
#include "zltabout.h"
Step2 定义 ZLTOUTTYPE 类型的变量并赋值为stdout:
ZLTOUTTYPE sout;
sout = (ZLTOUTTYPE)stdout;
Step3 使用 zltoutc 输出一个字符:
zltoutc(sout, _T(' '));
Step4 使用 zltouts 输出字符串:
static const TCHAR strEnd[] = _T("(END)");
zltouts(sout, strEnd, sizeof(strEnd)/sizeof(strEnd[0])-1);
Step5 使用 zltoutf 进行带缩进的格式化输出:
for(i=0; i<3; ++i) {
zltoutf(sout, i, _T("indent %d
"), i);
}
完整代码:
#include <stdio.h> #include <wchar.h> #include "auto_tchar.h" #include "auto_tmain.h" #define ZLTABOUTMODE 1 // ZLTABOUTMODE_C #include "zltabout.h" /// main . int _tmain(int argc, TCHAR* argv[]) { ZLTOUTTYPE sout; static const TCHAR strEnd[] = _T("(END)"); int i; // show. sout = (ZLTOUTTYPE)stdout; for(i=0; i<3; ++i) { zltoutf(sout, i, _T("indent %d "), i); } zltouts(sout, strEnd, sizeof(strEnd)/sizeof(strEnd[0])-1); zltoutc(sout, _T(' ')); return 0; }
输出结果:
indent 0 indent 1 indent 2 (END)
三、C++范例
Step 1 定义 ZLTABOUTMODE 宏 与 引入 zltabout.h:
#define ZLTABOUTMODE 2 // ZLTABOUTMODE_CPP
#include "zltabout.h"
Step2 定义 ZLTOUTTYPE 类型的变量并赋值为cout/wcout:
ZLTOUTTYPE sout;
#ifdef UNICODE
sout = dynamic_cast<ZLTOUTTYPEW>(&wcout);
#else
sout = dynamic_cast<ZLTOUTTYPEA>(&cout);
#endif
Step3 使用 zltoutc 输出一个字符:
zltoutc(sout, _T(' '));
Step4 使用 zltouts 输出字符串:
static const TCHAR strEnd[] = _T("(END)");
zltouts(sout, strEnd, sizeof(strEnd)/sizeof(strEnd[0])-1);
Step5 使用 zltoutf 进行带缩进的格式化输出:
for(i=0; i<3; ++i) {
zltoutf(sout, i, _T("indent %d
"), i);
}
完整代码:
#include <iostream> #include <sstream> #include <stdio.h> #include <wchar.h> #include "auto_tchar.h" #include "auto_tmain.h" //#define ZLTABOUTMODE 1 // ZLTABOUTMODE_C #define ZLTABOUTMODE 2 // ZLTABOUTMODE_CPP #include "zltabout.h" using namespace std; /** test mode (测试模式). * * values: * * 1: Test cout/wcout . * * 2: Test stringstream/wstringstream . * */ #define MYTESTMODE 2 /// Do Test. void dotest(ZLTOUTTYPE sout, int indent) { static const TCHAR strEnd[] = _T("(END)"); int i; for(i=0; i<3; ++i) { zltoutf(sout, indent+i, _T("indent %d "), i); } zltouts(sout, strEnd, sizeof(strEnd)/sizeof(strEnd[0])-1); zltoutc(sout, _T(' ')); } /// main . int _tmain(int argc, TCHAR* argv[]) { ZLTOUTTYPE sout; // show. #if ZLTABOUTMODE==ZLTABOUTMODE_DUMMY sout = (ZLTOUTTYPE)NULL; #elif ZLTABOUTMODE==ZLTABOUTMODE_C sout = (ZLTOUTTYPE)stdout; #elif ZLTABOUTMODE==ZLTABOUTMODE_CPP #if (MYTESTMODE==1) // test cout/wcout . #ifdef UNICODE sout = dynamic_cast<ZLTOUTTYPEW>(&wcout); #else sout = dynamic_cast<ZLTOUTTYPEA>(&cout); #endif #elif (MYTESTMODE==2) // test stringstream/wstringstream . basic_stringstream<TCHAR> ss; sout = dynamic_cast<ZLTOUTTYPE>(&ss); #endif #else #error Error ZLTABOUTMODE ! #endif dotest(sout, 0); #if (ZLTABOUTMODE==ZLTABOUTMODE_CPP) && (MYTESTMODE==2) // test stringstream/wstringstream part 2. basic_string<TCHAR> str = ss.str(); #ifdef UNICODE wcout << str; #else cout << str; #endif #endif return 0; }
注:还可以将ZLTOUTTYPE绑定到 stringstream,例如——
ZLTOUTTYPE sout; basic_stringstream<TCHAR> ss; sout = dynamic_cast<ZLTOUTTYPE>(&ss); dotest(sout, 0); basic_string<TCHAR> str = ss.str(); #ifdef UNICODE wcout << str; #else cout << str; #endif
四、快速参考
常用函数:
// Output stream's type (输出流的类型). #define ZLTOUTTYPE // C FILE* or C++ basic_ostream . // Writes a character to a stream (向流输出一个字符). int zltoutc(ZLTOUTTYPE sout, TCHAR ch); // Write a string to a stream (向流输出字符串). void zltouts(ZLTOUTTYPE sout, const TCHAR* str, size_t cch); // Formatted output with indentation using a pointer to a list of arguments (参数列表指针形式的带缩进格式化输出). void zltoutvf(ZLTOUTTYPE sout, int indent, const TCHAR* fmt, va_list argptr); //Formatted output with indentation (带缩进格式化输出). void zltoutf(ZLTOUTTYPE sout, int indent, const TCHAR* fmt, ...);
输入配置性宏:
* ZL_NOWIDE: 不定义宽字符版函数 . 用于提高兼容性, 例如bcb6.
* ZLTABOUTMODE: 输出模式. 值可以为 0(ZLTABOUTMODE_DUMMY), 1(ZLTABOUTMODE_C), 2(ZLTABOUTMODE_CPP) .