命令提示窗口输出汉字
问题:
命令提示窗口输出汉字不显示
原因:
Unicode 是字符集,只是用来表示字符以什么样的方式存储。
Locale 决定的是这些字符以什么样的编码方案输出。
//一个字符集可以有多个编码方案. 就拿windows来说,里面的unicode是UTF-16
按照C++的本地化和国际化的思想,其内部使用本地字符集或宽字符集,外部总是本地字符集,当使用宽版本的功能时,输入时总是要执行从本地编码到宽编码的转换,输出时执行从宽编码到本地编码的转换。locale对象代表了某一个地区的本地化信息,其中一个就是如何是转码。默认的locale是一个叫“C”的locale,其字符集相当于ascii,这样输出中文时,所ascii之外的编码就无法转换了。所以一定要设置成中文的locale。输入,文件I/o等也要注意这个问题。
由于在控制台下,系统默认的locale汉字集为GB码(指装有中文系统),在使用Unicode时,是系统帮忙将宽字符转换为多字节字符,因此在控制台程序中直接显示Unicode的汉字时,需要进行设置。
对策:
就是通过locale头文件中的setlocale函数 设置命令提示窗口的
CString strName = _T("宽字符输出");
setlocale(LC_ALL, "chs");
wcout<<strName.GetBuffer()<<endl;
解释:
setlocale用来設定或擷取執行階段的地區設定。
原型 : wchar_t *_wsetlocale( int category, const wchar_t *locale );
category
地區設定所影響的分類。
locale
地區設定規範。
http://www.cnblogs.com/zplutor/archive/2010/11/27/1889227.html
_wsetlocale是setlocale的宽字符版本,这两个函数的区别只在于返回值以及第二个参数使用的是否宽字符字符串,执行效果都是一样的。
要解释这段代码,首先要从控制台本身说起。凡是涉及到字符处理的地方都要用到字符集,而控制台是一个字符环境,因此控制台也需要使用字符集,它所使用的字符集叫做代码页,每一个代码页大致上对应一种自然语言,它定义了这种语言的字符如何与二进制代码相关联。例如,表示英语的代码页是437,表示简体中文的代码页是936。一个控制台窗口只能有一个活动代码页,所以不同语言的字符不能同时出现在一个控制台窗口中,除非这个字符是两者共有的,且有相同的二进制代码。可以通过chcp命令来改变当前控制台窗口所使用的代码页。
代码页实际上是一种多字节字符集,所以控制台本质上不支持Unicode。因此,如果直接向控制台输出宽字符,将不会得到正确的显示。必须先将宽字符转换成多字节字符,再进行输出。而wprintf函数在内部也的确是进行了这种转换,可以尝试一下在wprintf函数内单步执行,会看到执行过程最终到达wcstombs_s。
问题出现在转换的过程上。转换函数必须知道将宽字符的二进制代码转换成哪种代码页字符的二进制代码,如果选择的代码页与控制台的活动代码页不相符,那么同样也不会正确显示。上面的第一段代码正是由于没有选择合适的代码页,导致输出错误。而在第二段代码中,通过将区域设置为中国,告诉转换函数将宽字符转换成936代码页的多字节字符,这与控制台的活动代码页一致,所以就可以正确输出了。
这里简单介绍一下_wsetlocale函数。该函数设置C运行库使用的区域文化。区域文化影响到数字、货币以及时间等数值的显示格式,当然还有代码页。第一个参数指示使用区域文化的哪个方面,取值可以是LC_COLLATE,LC_CTYPE,LC_MONETARY,LC_NUMERIC,LC_TIME以及LC_ALL。例如,如果使用LC_NUMERIC,则C运行库输出数字的时候将使用指定区域文化的数字显示风格;如果使用LC_CTYPE,则只影响转换函数所选择的代码页。
第二个参数通过字符串指定区域文化。该字符串有一个固定的格式,详细情况可以参见MSDN文档。但一般情况下我们只需使用国家或地区的缩写即可,例如“chs”。如果使用空字符串“”,则表示根据当期操作系统的区域设置选择相应的代码页。所以如果操作系统选择的区域是“中文(中国)”,则也可以通过_wsetlocale(LC_ALL, “”)来设置正确的代码页。
C运行库默认使用一个名为“C”的区域文化,这是语言无关的,具有国际通用性,与其关联的代码页仅包含了ASCII中定义的字符。在程序启动的时候C运行库会以setlocale(LC_ALL, “C”)的方式调用setlocale,所以默认情况下wprintf不能正确输出含有中文的宽字符字符串。
C语言下对宽字符的输出处理就这样了。接下来看看C++对宽字符的输出处理。_wsetlocale只对C运行库有效,对cout和wcout是没有影响的。对于cout和wcout,应该使用其成员方法imbue:
std::wcout.imbue(std::locale("chs", std::locale::all));
locale对象构造方法的两个参数与_wsetlocale函数参数的意义是一样的,只是位置调转了。
与wprintf一样,wcout在输出宽字符字符串的时候,也是先将其转换成多字节字符字符串。不同的是,遇到代码页上不支持的字符的时候,wprint输出一个问号,而wcout无任何输出,同时将badbit和failbit置位,后续的输出全部都无效。个人认为wcout的处理方式欠妥,因为并不是所有场合都适合这样处理,还是wprintf的处理方式比较通用。
基于上面的讨论,我们在编写控制台程序时一定要非常小心地处理输入输出问题,确保程序的输出正确无误。
(在本文第一次发表的内容中,建议编写控制台程序应该使用多字节字符集,而不要使用Unicode字符集。这是一个明显错误的建议,因此将这段内容删去了。)
最后对在网上看到的将char*字符串转换成wchar_t*字符串的方法发表一下看法。该方法的代码如下:
#include <iostream>
#include <sstream>
using namespace std;
int main() {
wostringstream outStrStream;
outStrStream << "博客园";
wstring wstr = outStrStream.str();
wcout << wstr << endl;
}
具体思路是:将char*类型的字符串输出到wostringstream对象中,再通过该对象的str方法获取转换后的字符串。这种方法作出了假设:wostringstream对象会自动将char*字符串转换成wchar_t*类型字符串。注意在这段代码中,没有调用wcout.imbu方法设置区域文化,但仍然能够正确输出中文。
编译、执行这段代码都没有问题,看上去似乎是正确的。但是如果试图获取转换后的字符串的长度就出问题了:
#include <iostream>
#include <sstream>
using namespace std;
int main() {
wostringstream outStrStream;
outStrStream << "博客园";
wstring wstr = outStrStream.str();
wcout << wstr.length() << endl;
}
这段程序将输出6,而不是3。除了长度之外,使用at方法获取到的字符也不是“博客园”中的一个。实际上,对该字符串进行操作的结果几乎都是不正确的。
为什么会出现这种情况呢?可以通过观察一下outStrStream对象内部的数据来寻找答案。下图是执行outStrStream << "博客园"之后的内存数据:
红色框内的便是outStrStream对象内的数据。再来看看宽字符与多字节字符的“博客园”字符串在内存中的实际数据:
#include <iostream>
#include <sstream>
using namespace std;
int main() {
char* pStr = "博客园";
wchar_t* pWStr = L"博客园";
}
上面的图是wchat_t*类型的,下面的图是char*类型的。通过这几幅图,可以看到outStrStream对象内的字符串仍然是多字节字符类型的字符串,只不过每个字节扩展成了两个字节。这根本不是宽字符类型的字符串,所以即使不调用wcout.imbue也能正确输出中文。
命令提示窗口输出汉字相关推荐
- shell脚本将命令的输出结果赋值给变量
Shell 命令替换是指将命令的输出结果赋值给某个变量.比如,在某个目录中输入 ls 命令可查看当前目录中所有的文件,但如何将输出内容存入某个变量中呢?这就需要使用命令替换了. Shell 中有两种方 ...
- Script:优化crs_stat命令的输出
在10g RAC中我们常用crs_stat命令查看CRS资源的状态,但是crs_stat命令的输出并不完整.可以通过以下脚本来优化crs_stat的输出: ---------------------- ...
- 【Linux 内核】进程管理 ( 进程特殊形式 | 内核线程 | 用户线程 | C 标准库与 Linux 内核中进程相关概念 | Linux 查看进程命令及输出字段解析 )
文章目录 一.进程特殊形式 ( 内核线程 | 用户线程 ) 二.C 标准库与 Linux 内核中进程相关概念 三.Linux 查看进程命令及输出字段解析 一.进程特殊形式 ( 内核线程 | 用户线程 ...
- 【Java 虚拟机原理】垃圾回收算法 ( 设置 JVM 命令参数输出 GC 日志 | GC 日志输出示例 | GC 日志分析 )
文章目录 一.设置 JVM 命令参数输出 GC 日志 二.GC 日志示例 三.GC 日志分析 一.设置 JVM 命令参数输出 GC 日志 在 IntelliJ IDEA 的启动参数中设置 -XX:+P ...
- shell中使用echo命令改变输出显示样式
文本终端的颜色可以使用"ANSI非常规字符序列"来生成.举例: echo -e "\033[44;37;5m ME \033[0m COOL" 以上命令设置背景 ...
- python怎么输出文字_python怎么输出汉字
看Python简明教程,学习使用print打印字符串,试了下打印中文,不行. 编辑环境:IDLE 上网搜了下解决办法,各种说法,试了两种:print u"学习" print (un ...
- vs2017 linux so导出函数,将Visual Studio 2017中的Assembly和C ++与命令行和输出相结合
我正在尝试将这些语言结合起来用于测试目的.有没有人知道为什么,在构建项目后,当.asm文件在源文件夹中时,无法找到clear函数.下面显示的以下图像应该解释我的要求,我将进一步编辑. .586 ;Ta ...
- mac命令行将输出写入文件_如何在Linux中使用命令行将PDF文件转换为可编辑文本...
mac命令行将输出写入文件 There are various reasons why you might want to convert a PDF file to editable text. M ...
- windows资源管理器已停止工作后,使用命令提示窗口拷贝文件和运行exe程序
电脑异常现象: 需要从优盘拷贝NetAssist.exe软件至电脑进行运行,发现双击无法打开我的电脑和文件夹,点击提示的重新启动程序问题后仍存在,重启电脑.关机再开机该问题依然存在.插入优盘后可以识别 ...
最新文章
- Slf4j 包老冲突,每次排查半天,是什么原因?怎么解决?
- 瞄准医疗数据安全四大风险 东软DBA如何绝地阻击
- python装饰器-python中的装饰器常用于哪些应用场景
- js实现简单的循环打字效果(思路分享)
- Windows驱动开发学习笔记(五)—— SSDT HOOK
- tensorflow独热编码方法_吴恩达课后作业学习2-week3-tensorflow learning-1-基本概念
- 华硕无双新品首爆:H45标压处理器+全球首款2.8K 120Hz OLED屏
- Unity3d之求物体体积
- 每一个创业的人,你要解决的就是流量
- pythoncharm如何安装opencv_Pycharm Opencv环境配置
- Senparc.Weixin.MP SDK 微信公众平台开发教程(十):多客服接口说明
- 创业篇——小老板的日常管理
- 进程间通信-命名管道FIFO
- java 高级工程师要求
- WinForm超市商品管理系统
- imagenet2012 对应 label
- mysql索引失效的几种情况分析
- 大学生bootstrap框架网页作业成品 bootstrap响应式网页制作模板 学生海贼王动漫bootstrap框架网站作品
- 中国石油沥青行业市场供需与战略研究报告
- cmd脚本(WIN10下)
热门文章
- PHP小V脸蛋白线,HPH小v脸蛋白线好不好用?HPH小v脸蛋白线怎么用
- 美国证券业托管和清算机构的发展与现状
- 招银网络 Java开发-HR面
- http请求gmt时间_HTTP日期/时间格式
- Docker部署rabbitmq遇到的两个问题
- 创宇滤镜|API防刷|短信邮件接口防刷|验证码防刷|搜索防刷 - 知道创宇云安全
- Bandizip Archiver for mac(便捷解压缩软件)
- 积分商城系统业务逻辑思维导图_怎么开发积分商城系统_OctShop
- 全球与中国无线门铃对讲设备市场深度研究分析报告
- 小明开了一家糖果店。他别出心裁:把水果糖包成4颗一包和7颗一包的两种。糖果不能拆包卖