首先给个验证均无问题的c++模板:验证环境windows 7 + vs2012; ubuntu 12.04 + g++(4.6.3); 当然也适用c语言
此c++模板编码最好为utf-8
// 注意,此文档最好采用utf-8编码
#include
#include
#include
int main()
{
//此语句重要,在win7 + vs2012和 ubuntu 12.04测试结果一致
//只要打印wchar_t字符,均加此语句,至少不会出错,此语句最好在程序初始化处
setlocale(LC_ALL, "");
// wprintf和printf最好不能同时使用.
// 如下使用printf同时打印了char字符串和wchar_t字符串
// 因此只采用printf是比较好的方法
wchar_t ws[] = L"国家";
printf("printf content start: %ls\n", ws);
printf("content end\n");
return 0;
}
用上面代码的原因:
1. 从后面我的实验可以看到, 有八种组合方式, 唯独选择这么一种是有原因的.
2. wprintf 和 printf 通用会遇到莫名其妙的问题,
3 . printf可以打印char, 使用格式为小写%s, 也可以打印wchar_t, 使用格式为%ls 或者 大写%S
4. 只要源文件编码为utf-8, 上面的代码就是跨操作系统和编译器平台的, 并且可以统一用一种方式打印char 和 wchar_t 字符串
得出上面结论的原因见下面:
下面为比较细节的讨论。
关于编码字符集:简单理解为,ascii码表达了美国英文字符,为一字节.
为了统一世界文字编码,出了unicode,如ucs-2,ucs-4,分别为16字节和32字节
因为历史包袱,unicode不可能完全替代以前的编码,所以出了有使用性的UTF-8编码,字节大小不定。
如何快速查看一个文字编码?如“国“字的utf-8编码是什么? 简单方法是新建一文件,记事本输入“国”, 记事本另存为,选择文件编码。 然后使用如下方式打开此文件,1:使用winhex软件 2. 使用notep++,选中文字”国“,点击菜单插件->converter->ascii to hex, 3, 其它.... (在线的就算了,我看了百度两个排名前两位的网站根本不是转的UTF-8, 而是转成了ucs-2,虽然其号称是转换成UTF-8)
如下表格是使用wchar_t的总结,其中编码格式设置是通过notepad++的格式菜单进行的,如下表格的测试代码后面会贴出来。
表格解释:
1.采用ansi编码方式,在ubuntu下会出错,另外通过g++ -Wall -finput-charset=ISO-8859-1 test.cpp 方式可以指定输入文件格式,但是这样很麻烦,因为首先要知道文件的格式是什么,在ubuntu下 通过file test.cpp 命令可以查到,我把ISO-8859-1到ISO-8859-16都试了,文件编码格式ANSI(即ISO8859-XX)且文件中有L"国家" 类似字符,编译不会通过,或者通过-finput-charset=xxx指定文件格式编译通过后输出也不对,故太麻烦。
2.在windows下和ubuntu下都通过的方式是文件编码采用UTF-8。
3.printf和wprintf不能混用,即一个程序中使用了printf, 就不使用wprintf,反之也是,既然printf输出char 和 wchar_t字符都可以,所以统一使用printf是最佳选择。
当然使用printf打印wchar_t时格式不一样,是%ls 或大写的%S, 例如: printf("wide char: %ls\n", ws);
4. 一旦要打印中文字符,在程序初始化时加一句setlocale(LC_ALL, ""); 否则打印中文会出错。
5. windows 对 字符串的内部编码比较统一,char的编码都成ANSI,如 char s[] = "国家", s里存的是”国家”的ANSI编码
wchar_t的编码都成UCS-2,如 wchar_t ws[] = L"国家", s里存的是”国家”的UCS-2编码
UBUNTU 对字符串的处理不是很统一,char 字符串的编码是随着文件编码格式有所变化,如文件为ansi,则ubuntu也为ansi,文件为UTF-8, 则char s[] = "国家" 里的也是 UTF-8编码。
wchar_t 则默认采用ucs-4编码。
总结:源代码文件编码用UTF-8, 打印采用printf是跨平台(操作系统,编译器), 跨char和wchar_t的最佳解决方案之一,另外不能忘了 setlocale(LC_ALL, "");
说的再多,不如自己测试下,如下为测试代码,一共有5种case,每次注释掉其他case,留要测试的case,并按照case注释处更改文件编码方式便可, 更改编码方式采用notepad++最方便了.
#include
#include
#include
#include
#include
// 测试运行环境:
// ubuntu 12.04 + g++ 4.6.3(或gcc,改文件后缀就行)
// windows 7 + vs2012
// 说明,在注释中说的编码E59BBD,是按照打印结果从低字节到高字节排练,并不一定和实际
// 的编码大小端一致。
int main()
{
//此语句重要,在win7 + vs2012和 ubuntu 12.04测试结果一致,只要打印wchar_t字符,均加此语句,否则出错。
setlocale(LC_ALL, "");
/****************** case 1 **********************************/
// 文件utf-8编码, 字符串不加L
// ubuntu : ws是utf-8编码: 如"国":E59BBD; 打印结果:国家
// windows: ws是ansi编码: 如"国":b9fa; 打印结果: 国家
/* char ws[] = "国家";
char *p = (char *)ws;
int i = 0;
printf("sizeof(ws) is %d\n", sizeof(ws));
for (; i < sizeof(ws); i++){
printf("byte: %x\n", p[i]);
}
printf("content start\n");
printf("%s\n", ws);
printf("content end\n"); */
/****************** case 2 **********************************/
// 2: 文件ansi编码, 字符串不加L
// ubuntu : ws是ansi编码,如"国":b9fa; 打印结果:无,出错
// windows: ws是ansi编码: 如"国":b9fa; 打印结果: 国家
/* char ws[] = "国家";
char *p = (char *)ws;
int i = 0;
//setlocale(LC_ALL, "zh_CN.UTF-8");
printf("sizeof(ws) is %d\n", sizeof(ws));
for (; i < sizeof(ws); i++){
printf("byte: %x\n", p[i]);
}
printf("content start: %s\n", ws);
printf("content end\n"); */
/****************** case 3 **********************************/
// 3: 文件utf-8编码, 字符串加L, 必须采用wchar_t, 用char编译器报错, 用wprintf打印
// ubuntu : ws是ucs-4编码,如"国":0x000056fd; 打印结果:国家
// windows: ws是ucs-2编码: 如"国":0x56fd; 打印结果: 国家
/* wchar_t ws[] = L"国家";
char *p = (char *)ws;
int i = 0;
wprintf(L"sizeof(ws) is %d\n", sizeof(ws));
for (; i < sizeof(ws); i++){
wprintf(L"byte: %x\n", p[i]);
}
wprintf(L"wprintf content start:\n"); //必须用wprintf, 且wprintf和printf不能同时使用.
wprintf(L"%ls\n", ws);
wprintf(L"content end\n"); */
/****************** case 4 **********************************/
// 4: 文件utf-8编码, 字符串加L, 必须采用wchar_t, 用char编译器报错, 用printf打印
// ubuntu : ws是ucs-4编码,如"国":0x000056fd; 打印结果:国家
// windows: ws是ucs-2编码: 如"国":0x56fd; 打印结果: 国家
wchar_t ws[] = L"国家";
char *p = (char *)ws;
int i = 0;
printf("sizeof(ws) is %d\n", sizeof(ws));
for (; i < sizeof(ws); i++){
printf("byte: %x\n", p[i]);
}
printf("printf content start:\n"); //wprintf和printf不能同时使用.
printf("%ls\n", ws);
printf("content end\n");
/****************** case 5 **********************************/
// 5: 文件ansi编码, 字符串加L, 必须采用wchar_t, 用char编译器报错
// ubuntu : 编译不通过
// windows: ws是ucs-2编码: 如"国":0x56fd; 打印结果: 国家
/* wchar_t ws[] = L"国家"; // 文件ansi编码,ws是unicode编码: 如国:56fd
char *p = (char *)ws;
int i = 0;
wprintf(L"sizeof(ws) is %d\n", sizeof(ws));
for (; i < sizeof(ws); i++){
wprintf(L"byte: %x\n", p[i]);
}
wprintf(L"wprintf content start:\n"); //必须用wprintf, 且wprintf和printf不能同时使用.
wprintf(L"%ls\n", ws);
wprintf(L"content end\n"); */
while(1); //方便看结果
return 0;
}