C++输出中文字符 C/C++多字节字符与宽字符的输出

2023-10-28

原文:http://www.cnblogs.com/lixiaohui-ambition/archive/2012/07/17/2596490.html

C++输出中文字符

1. cout


场景1
: 在源文件中定义 const char* str = "中文" 在 VC++ 编译器上,由于Windows环境用 GBK编码,所以字符串 "中文" 被保存为 GBK内码,
编译器也把 str 指向一个包含有 GBK编码的只读内存空间.
用 cout 输出 str 时, 由于中文Windows环境用GBK编码,所以把GBK编码的 str 内容输出到控制台,没问题.

场景2: 在Linux 下编辑一个文件 const char* str = "中文", 由于Linux普遍使用 UTF8 编码,所以在源文件里, "中文" 被保存为 UTF8内码.
然后在Windows中打开这个源文件,由于Windows使用GBK编码,所以VC++ 按照GBK去解释被保存为 UTF8 内码的 "中文", 显示为乱码.

2. wcout

在源文件中定义 const wchar_t* str = L"中文" 在 VC++ 编译器上,由于指定了L,所以字符串 "中文" 被保存为UNICODE内码(UCS2),编译器也把 str 指向一个包含有 UNICODE 编码的只读内存空间.
用 wcout 输出 str 时, wcout 首先调用 wcstomb_s() (即根据当前 local 转换, 如果没有设置local,则是经典的C local, 不认识中文)把 str 的内容转换后交给控制台,结果自然什么都不显示. (调试代码可以知道VC++ 2010 实现是一个字符一个字符输出,调用 wctomb_s)

原理
我们知道 cout 和 wcout 分别是 basic_ostream 的特化版本, 而 basic_ostream 调用 basic_streambuf 实际执行输出动作,针对 wchar_t,basic_streambuf有专门的特化函数,调用 fputwc 输出一个宽字符,而 fputwc 需要调用 wctomb_s 把宽字符转换后再输出. 我们知道wctomb_s 是依赖 locale 的,由于默认情况下是C locale,所以用中文内码调用 wctomb_s 会失败.

解决办法
设置当前系统的locale 替代默认的 "C" locale, 使 wctomb_s 等函数可以正常工作.
以下3种方法中的任意一种都可以达到目的.

1. C函数设置全局locale
setlocale(LC_ALL, "");

2. C++ 设置全局locale
std::locale::global(std::locale(""));

2. 单独为 wcout 设置一个 locale
std::locale loc("");
std::wcout.imbue(loc);

结论
和Windows API 不同 C++中的各种 w版本的类或者函数并不能提高性能,因为它们都需要用 wc..to..mb 之类的函数转换为ANSI兼容编码然后调用标准库函数.或者,如果库函数的实现者愿意,针对Windows系统,宽字符的fputwc可以直接调用UNICODE版本的Windows API而不用转换.但是这些都跟C++语言本身没有什么关系.由于Windows内核是UNICODE的,所以直接用 UNICODE 字符串调用 Windows API会有一点点好处.

C++设计者的出发点: 我不管你用什么字符编码,与C++无关,要输出时:如果是单字节字符或者多字节字符,直接输出;如果是宽字符,则根据local转换为多字节字符,然后再输出.
即使将来UNICODE过时了(假设,假设而已),也不要紧,只要定义好新的local即可.对于C语言也是这样.

Windows设计者的出发点: 统一使用 Unicode 宽字符,解决一切问题



原文:http://blog.csdn.net/gonxi/article/details/5931006

C/C++多字节字符与宽字符的输出

使用C++标准库的iostream,可以方便地将控制台、文件、字符串以及其它可扩充的外部表示作为流来处理,但要处理中文,却会碰到很多问题。本人原来没怎么用过这个iostream,这几天尝试用这个写点东西,一会儿不能输出中文,一会儿不支持中文文件名的,搞得头大。网上搜了搜,没有发现适用于所有情况的解决方案。不过后来自己经过多次测试,基本解决了这些问题,现在写成文字作为一个总结,也供碰到同样问题的朋友参考。关于C语言中的 printf和wprintf的中文输出,本文也进行了探讨。

  需要说明的是,我的开发环境是VS 2005(标准库当然也是微软实现的),不保证其它环境下是相同的效果。
1、cout和wcout
  在缺省的C locale下,cout可以直接输出中文,但对于wcout却不行。对于wcout,需要将其locale设为本地语言才能输出中文:
  wcout.imbue(locale(locale(),"",LC_CTYPE)); // ①
  也有人用如下语句的,但这会改变wcout的所有locale设置,比如数字“1234”会输出为“1,234”。
  wcout.imbue(locale(""));

2、ofstream和wofstream
  在缺省的C locale下,ofstream能正确输出中文到文件中,但不支持中文文件名;wofstream支持中文文件名,但不能向文件中输出中文。要解决这个问题,需要在打开文件之前将全局locale设为本地语言。将全局locale设为本地语言后,ofstream和wofstream的问题都解决了,但 cout和wcout却不能输出中文了。要让cout和wcout输出中文,需要将全局locale恢复原来的设置,如下所示:
  locale &loc=locale::global(locale(locale(),"",LC_CTYPE)); // ②
  ofstream ofs("ofs测试.txt");
  wofstream wofs(L"wofs测试.txt");
  locale::global(loc); // ③
  ofs<<"test测试"<<1234<<endl;
  wofs<<L"Another test还是测试"<<1234<<endl;

3、printf和wprintf
  加上这两位C语言中的老兄,问题更加复杂。考虑如下语句(注意s的大小写):
   printf("%s", "multibyte中文/n"); // ④
   printf("%S", L"unicode中文/n"); // ⑤
   wprintf(L"%S", "multibyte中文/n"); // ⑥
   wprintf(L"%s", L"unicode中文/n"); // ⑦
  缺省情况下,⑤、⑦两条语句不能输出中文,这两条语句中字符串的形式是unicode形式的。如果在所有输出语句之前加上如下语句将C语言的全局locale设置为本地语言(C语言中只有全局locale)就可以正常输出了:
  setlocale(LC_CTYPE, ""); // ⑧
  但这会导致cout和wcout不能输出中文,将C语言的全局locale恢复后cout和wcout就正常了,如下所示:
  setlocale(LC_CTYPE, "C"); // ⑨
  但恢复后,printf和wprintf输出Unicode文本又不正常了(输出MultiByte文本总是正常的)。总不能每写一个 printf/wprintf就设置一次然后再恢复一次吧?所以,建议不要混用iostream和printf/wprintf,实在要混用,那就让 printf/wprintf只输出MultiByte字符串,这样不需要调用setlocale(),也就不会影响到cout和wcout。

总结
  总之,用iostream、printf/wprintf输出中文,有点麻烦。概括起来要点如下:
如果要用wcout,需要在使用之前按语句①将其locale设置为本地语言; 
如果要用ofstream或wofstream,要在打开文件之前按语句②将全局locale设为本地语言并保存初始的全局locale。然后在打开文件之后,按语句③将全局locale恢复为初始值; 
不要混用iostream和printf/wprintf。如果要混用,只用printf/wprintf输出MultiByte字符串; 
单独使用printf/wprintf时,如果要输出Unicode字符串,需要按语句⑧设置C语言的全局locale。如果只输出MultiByte字符串,则不需设置。 

最后再加上转帖者(本站站长)的一点话:
  一个程序,一般不会用两种字符串, 要么用多字节字符串, 要么用宽字符串. 这样,问题其实就很简单, 没作者说得那么复杂.. 就算有时候需要转换, 也有专门的函数
(例如,多字节字符版本的程序,使用COM组件, COM组件需要宽字符串. 则可以利用 _bstr_t, CString)..

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C++输出中文字符 C/C++多字节字符与宽字符的输出 的相关文章

随机推荐

  • 【送面试题】如何高效实现MyBatis批量更新MySQL数据:List入参的完美解决方案

    AI绘画关于SD MJ GPT SDXL百科全书 面试题分享点我直达 2023Python面试题 2023最新面试合集链接 2023大厂面试题PDF 面试题PDF版本 java python面试题 项目实战 AI文本 OCR识别最佳实践 A
  • EfficientDet阅读笔记

    EfficientDet Scalable and Efficient Object Detection 2020 IEEE CVF Conference on Computer Vision and Pattern Recognition
  • 在vue里使用reset.css

    在vue里使用reset css 1 搜索reset css并下载 2 在vue项目的src下的assets目录里放入下载好的reset css 3 在main js入口文件里导入reset css 以上工作都做完之后css样式就可以正常生
  • 前端埋点的简单实现

    要记录用户的浏览轨迹 知道用户都浏览了哪些页面 在每个页面都停留了多长时间 还有 比如用户所用的手机型号 等个人信息 个人信息获取的接口如下 在用户刚进入时获取用户信息 3 安装 js cookie 插件 npm install js co
  • SyntaxHighlighter与ajax公用的时候不能正常显示代码高亮的解决方法

    SyntaxHighlighter是当前比较流行的一个高亮显示代码的插件 但今天在与ajax使用的时候遇到了无法正常高亮显示的问题 参考了http stackoverflow com questions 6471526 use syntax
  • react获取全局_react学习笔记

    一 开发 个人之前也粗略看过react的文档 但是程序员最怕的就是没有项目实操 看完后一段时间就全忘了 但是现在市面上react的使用又很多 我太难了 最近因为疫情只能呆在家里 刚好利用这段时间搞一搞 当然也是粗略的搞 做完一个大屏展示后
  • matlab求函数的极小值和零点,函数的根、极小值原来可以这么求!

    今天给大家介绍MATLAB命令fzero和fminbnd fzero可以用于寻找一个函数的零点 fminbnd可以用于寻找一个函数的最小值 以下面这个函数为例 先用户自定义函数把上面的函数叫为func 并存入func m的M文件中 其文件内
  • Ceph论文译文--Ceph:一个可扩展,高性能分布式文件系统

    译者注 本文是出于作者对于ceph的兴趣 在开源中国上关注ceph翻译 没有看到ceph论文的相关翻译 索性在阅读过程中把它翻译了出来 花费了几个周末时间 翻译过程中收获颇多 现把译文分享出来 如对您有益则倍感荣幸 肯定有很多不足之处 如有
  • CentOS 7下go环境配置(超多问题)

    文章目录 1 安装Visual Code 2 获得golang安装包并安装 3 第一个GO语言程序 hello go 4 安装必要工具与插件 1 安装Visual Code 在终端中安装VScode 使用以下命令 sudo rpm impo
  • matplotlib画图、标点、打标签

    Rendering 这是想要的效果 Notes 记录几个功能的做法 函数作图 座标轴 下 左边框 移到过原点 上 右边框去掉 标出一个点 虚线描出这个点的横 纵坐标所在 给这个点打标签 图片标题 保存 Code import matplot
  • 一款优秀持久层框架Mybatis详解!

    Mybatis ssm框架 配置文件的 最好的方式 看官方文档 1 简介 1 1 什么是Mybatis MyBatis 是一款优秀的持久层框架 它支持定制化 SQL 存储过程以及高级映射 MyBatis避免了几乎所有的JDBC代码和手动设置
  • CTF-杂项与密码学总结

    杂项 01文件操作与隐写 文件类型识别 1 File命令 当文件没有后缀名或者有后缀名而无法正常打开时 根据识别出的文件类型来修改后缀名即可正常打开文件 使用场景 不知道后缀名 无法打开文件 格式 file myheart 2 winhex
  • 怎么将服务器中图片显示出来,服务器显示图片

    服务器显示图片 内容精选 换一换 将图片导入图片索引库 该图片可以是同一区域OBS桶内的图片或请求消息体里的图片 只有导入图片索引库的图片方可被搜索到 添加或搜索的图片存储在OBS的桶中时 需要对OBS的桶授权 在图像搜索服务管理控制台实例
  • sublim python提示插件

    python解释器的路径 python interpreter C Users xy AppData Local Programs Python Python36 32 python exe 去掉白框 anaconda linting fa
  • SpringCloud服务发现-ribbon

    服务消费者 api order add 通过 eureka 查找服务提供者 order add 通过服务调 组件调 提供者 创建springboot应用 添加依赖 eureka server ribbon 配置application yml
  • 智能车图像处理20-进阶篇12--正入十字补线1

    前言 希望大家多多点赞评论收藏哦 不懂的地方评论区留言就好 这篇文章主要讲述基本的正入十字补线方法 场景图 效果图 一 函数主体 思路讲解 void buzhongxian2 secondmid 0 if
  • 基于减法优化SABO优化ELM(SABO-ELM)负荷预测(Matlab代码实现)

    欢迎来到本博客 博主优势 博客内容尽量做到思维缜密 逻辑清晰 为了方便读者 座右铭 行百里者 半于九十 本文目录如下 目录 1 概述 2 运行结果 3 参考文献 4 Matlab代码及数据 1 概述 基于减法优化的 SABO ELM Sub
  • IDEA反编译jar包源码

    1 maven 项目查看jar源码 如何在idea中查看jar包源码 文章目录 准备jar包 idea打开文件夹 最后一步 准备jar包 例如 我准备看resin的jar 在桌面准备了一份 idea打开文件夹 在idea中file gt o
  • spring redis 永不过期_Springboot-Redis分布式锁

    随着现在分布式架构越来越盛行 在很多场景下需要使用到分布式锁 分布式锁的实现有很多种 比如基于数据库 zookeeper 等 本文主要介绍使用 Redis 做分布式锁的方式 并封装成spring boot starter 方便使用 一 Re
  • C++输出中文字符 C/C++多字节字符与宽字符的输出

    原文 http www cnblogs com lixiaohui ambition archive 2012 07 17 2596490 html C 输出中文字符 1 cout 场景1 在源文件中定义 const char str 中文