结果仍然失败
百思不得其解,最后从网上搜到两种能正常输出的办法
// 1
setlocale(LC_ALL,"chs");
wprintf(L"%d, %s, %s, %d \n",rs.m_ID, rs.column1, rs.column2, rs.column3);
// 2
DWORD ws;
WriteConsoleW(GetStdHandle(STD_OUTPUT_HANDLE),line,wcslen(line),&ws,NULL);
果断把问题搜到底。查到以下两篇好文,直接搬上来。
以下是网上转载的两篇文章:
-----------------------------------------------------------------------
一、转自http://blog.csdn.net/hikaliv/article/details/4570956.
文 / 李博(光宇广贞)
图一
实验平台信息见:《测试 VS 2010 对 C++ 0x 标准的谨慎支持》。
先说两组概念:字符集(CharSet)与编码方案(Encoding Scheme)、源代码文件编码(Source file CharSet)与程序文件编码(Exec file CharSet)。
第一组,字符集与编码方案:
字符集就是字符的数字代码集。有 ANSI/ASCII、MBCS(Multibytes)、Unicode 等。比如“汉”字 Unicode 代码为 0x6c49。
编码方案就是记录字符代码的方式。有 UTF-8、UTF-16、GB2312 等。编码方案分“变长编码”与“定长编码”两种。UTF-8 是变长编码,模板如下:
0x0000 – 0x007F 表一字节 0xxxxxxx
0x0080 – 0x07FF 表两字节 110xxxxx 10xxxxxx
0x0800 – 0xFFFF 表三字节 1110xxxx 10xxxxxx 10xxxxxx
比如 UTF-8 编码序列 11100110 10110001 10001001,由首字节判断为三字节模板,解析时连续读取三字节并将编码模板去除,剩 0110 110001 001001,连在一起即为 01101100B 01001001B,也即 0x6c49,即“汉”字。
字符集与编码方案概念分明,却互依互存。字符集与编码方案是配套的。比如提到 GB2312 编码,即是指 GB2312 字符集与 GB2312 编码方案。此处 GB2312 为两字节定长编码。而提到 Unicode 编码,即指 Unicode 字符集与 UTF-X 编码方案。其中 UTF-16 为两字节定长编码,UTF-8 设计为变长是为了工业应用中兼容已有的 ANSI/ASCII 编码,并广泛应用于互联网业务。
双字节定长编码为了与单字节编码区分,注意到单字节编码最高位为 0,故设定首字节最高位为 1,指示解析器需要连续读取两字节。
第二组,源码编码与程序编码:
源码文件与生成的程序文件编码是两回事儿。源码文件编码是文本文件保存时指定的编码;而程序文件编码依赖系统环境设置。
第二组问题的焦点在于“常量字串”的处理上。常量字串在代码中是用源码文件编码记录的;而编译时将如何处理呢?这就讨论到了 cout 与 wcout 之不同。
cout 与 wcout 有何不同?图一可见前两行正确显示,后两行显示异常。显示异常当然是因为常量字串处理出了问题。
再说两组概念:Multibytes 与 Uniocde、Win OS 之 wchar_t 与 ANSI/ISO C/CPP 之 wchar_t。
第一组、Multibytes 与 Uniocde:
VC 下,或者说 Win32 中,二者之别等价于变长与定长编码之分,或者说是采用非 UTF-16 还是 UTF-16 之分。自 Win2k 以降,基于 WinNT 内核的 Win OS 已全面更新为 UTF-16 编码。此处 Unicode 仅指 Unicode 字符集配 UTF-16 编码。其余,包括 UTF-8、UTF-7、GB2312、ANSI/ASCII 等一律划归 Multibytes。故而 Multibytes 应理解为“变长”字符,而非“多”字符。
二者转换,WinApi 提供 MultiByteToWideChar 和 WideCharToMultiByte 方法。转换的依据是 CodePage。对此,MSDN 上有细目可查。比如 MS936 码页便是 GB2312 与 Unicode 的映射关系表。
第二组、Win OS 之 wchar_t 与 ANSI/ISO C/CPP 之 wchar_t:
ANSI/ISO C/CPP 中 wchar_t 表示长于 8-bit 的数据类型,至于多长,具体依赖实现。《Unicode 标准 4.0》如是说:
“ANSI/ISO C leaves the semantics of the wide character set to the specific implementation but requires that the characters from the portable C execution set correspond to their wide character equivalents by zero extension.”
“The width of wchar_t is compiler-specific and can be as small as 8 bits. Consequently, programs that need to be portable across any C or C++ compiler should not use wchar_t for storing Unicode text. The wchar_t type is intended for storing compiler-defined wide characters, which may be Unicode characters in some compilers.”
标准可没说 wchar_t 表示的一定是 Unicode 编码,GB2312 也应可由 wchar_t 表示。只不过Win32 下 wchar_t 锁定为 UTF-16,而 Unix-like 通常为 UTF-32。对于亚欧主要文明体的文字,UTF-16 已经足够。
在 VC 下,常量字串 "" 对应 const char* 型,L"" 对应 const wchar_t* 型。前者用来处理各种 Multibytes;而后者指定处理 UTF-16。对应的 cout 与 wcout、string 与 wstring、iostream 与 wiostream 等亦如此。
- "没有共产党,就没有新中国!" 字串,按系统环境默认编码处理,此处为 GB2312。
- L"伟大领袖毛主席,万岁、万岁、万万岁!" 宽字串,由于指定了 L,因此该字串将转成 UTF-16 码流传给 wcout。注意其上一行指定了 chs 环境,也即 MS936 CodePage 映射,因此系统将 UTF-16 码流转为 GB2312 码流输出到控制台缓存(控制台为 I/O 终端文件)。
- "Let's Fuck 亚米利加合众国!" 字串,系统将传给 wcout 的系统默认编码流误当成 UTF-16 码去解码为 GB2312,由于英文字符二者对应,显示正常,而汉字编码不对应,造成汉字显示异常。
- L"USA Idiot" 宽字串的显示问题则与编码无关,cout 的 <<算符重载不认识 const wchar_t* 型数据,因此将此操作误当成取址输出,输出的便是该常量字串的地址。
最后一个问题,工程属性可以设置字符集为 Multibytes 或 Unicode。这是用来切换 Winapi 版本的,是用 Ansi 版本或 Unicode 版本。
W 系列流操作对像有何用呢?使用 wcout 比 cout 优势在哪儿呢?见如下例:
图二
生成一个按倭文编码保存的文件 e:/Fck.txt。然后将那句歌词在控制台上显示出来。已知系统默认环境为 GB2312 编码。因此通过 w 系列流操作对像,通过 932、936 两页码映射,以 Unicode 流为中介,将 shift_jis 码流转成 gb2312 码流,在控制台终端正常显示。这活儿,用 cout 办不到。
那 cout 不就没用了么?可以废掉它了。不!见如下示例:
- wcout.imbue ( locale ( "chs" ) );
- wcout <
- // 第四行是另一个程序,与前两行无关,不受第一行约束
- wcout <<"打倒苏修正主义!" <
第 2 行代码一句输出,首先 L 将字串转码成 UTF-16 流,然后向控制台输出时,还要根据 wcout.imbue 方法指定映射再转码一次。第 4 行,没有加 L,编译时按系统默认环境编码传给 wcout,但此时,wcout 会误将之用做 UTF-16 码流。尽管直接输出给控制台,由于未指定映射,码流被原封不动地冲入缓存,由于前后均为系统默认环境编码,因此显示正常;但此用法是极为危险的,因为其它使用 wcout 对像做转码操作将会失败。
对于不需要跨文字系统平台的应用来说,使用 wiostream 多此一举,iostream 即可,比如自产自销的本机应用。若考虑到国际化,则应全部使用 w 系列流操作对像。MSDN 鼓励使用 wiostream。
---------------------------------------------------------------------
二、转自http://www.cppblog.com/sandy/archive/2006/06/21/8779.html
1. printf 只能提供ANSI/MB 的输出,不支持输出unicode stream.
例如:
wchar_t test[]=L"测试1234";
printf("%s",test);
是不会正确输出的
2.wprintf 同样不会提供unicode output,
但是他会把wchar_t的string转为locale的SB/MB字符编码,然后输出
例如:
wchar_t test[] = L"测试Test";
wprintf(L"%s",test);
会输出??1234之类的字符串,或者不输出任何结果
因为wprintf没有办法把L"测试Test"转为默认的ANSI,需要设置locale
setlocale(LC_ALL,"chs");
wchar_t test[] = L"测试Test";
wprintf(L"%s",test);
会有正确的输出
等同于printf("%ls",test);
综上:
CRT I/O functions do not provide Unicode output.
3. Window console自从NT4就是一个真正的unicode console
不过输出unicode string,只有使用Windows API, WriteConsoleW
例如:
wchar_t test[] = L"测试1234";
DWORD ws;
WriteConsoleW(GetStdHandle(STD_OUTPUT_HANDLE),test,wcslen(test),&ws,NULL);
可以正确的输出而不需要设置locale,因为是真正的unicode的输出,跟codepage无关
4. 如何实现跨平台的console output
不要使用wchar_t和wprintf,因为这些都依赖于编译器.
ICU是IBM的一个成熟的跨平台支持unicode的libary,推荐使用
以下是ICU的uprintf实现
void uprintf(
const UnicodeString &str) {
char *buf = 0;
int32_t len = str.length();
int32_t bufLen = len + 16;
int32_t actualLen;
buf =
new
char[bufLen + 1];
actualLen = str.extract(0, len, buf
/*
, bufLen
*/);
//
Default codepage conversion
buf[actualLen] = 0;
printf("%s", buf);
delete buf;
}
它也是先把Unicode string转化为本地的codepage,然后printf,虽然也不是unicode output,但是跨平台,大多数情况会工作得很好。