c/c++ linux下输出中文(宽字符)
同样,使用的是VS FOR LINUX进行测试。
converting to execution character set: Invalid or incomplete multibyte or wide character
如果编译时候遇到该错误,则可以加上-finput-charset
-fexecute-charset
g++编译选项解决。因为linux下gcc希望源文件是UTF-8格式,所以都改成UTF-8就好了。同时,也可以vs下装个forceUTF8插件。
搜了下,网上有说使用wprintf的,比如:
wchar_t c= L'中国';
wprintf(L"%c",c);
wprintf(L"%ls\n", L"中华人民共和国");
测试的时候发现wprintf没有打印任何东西。
有说使用locale loc("chs");的:
locale loc("chs");
wcout.imbue( loc );
也有说setlocale( LC_CTYPE,"chs");的
使用chs编码,运行时就报异常了,难道都没测过么???
最后还是自己逐个调试解决了。如下:
setlocale(LC_ALL, "zh_CN.UTF-8"); wchar_t zh_cn = L'国'; wchar_t zh_cns[] = L"中国"; wchar_t another_w[sizeof(zh_cns)/sizeof(wchar_t)] = {0}; wcscpy(another_w, zh_cns); printf("%ls。。。....%ls。。。%lc\n", zh_cns, another_w,zh_cn);
加上-finput-charset
-fexecute-charset
g++编译选项或者在VS中把文件设置为UTF-8带签名格式即可。
关于locale的格式,windows和linux下不完全一样,主要是早期ms和posix并不兼容,可以参考https://blog.csdn.net/jhsword/article/details/94141589,这是跨平台要注意的点之一。
输出:
中国。。。....中国。。。国
最后,宽字符的操作函数和char不同,常用的可以参考http://www.cnblogs.com/lidabo/p/6912788.html。
上述设置后,环境中就是指定的字符集了,但是vs监视窗口仍然会是显示16进制,如下:
经查帖子https://blog.csdn.net/lainegates/article/details/72236321,将C:\Program Files (x86)\Microsoft Visual Studio 14.0\Common7\Packages\Debugger\Visualizers\stl.natvis的
将文件583-586行改为如下:
<DisplayString Condition="_Mypair._Myval2._Myres < _Mypair._Myval2._BUF_SIZE">{_Mypair._Myval2._Bx._Buf,s8}</DisplayString> <DisplayString Condition="_Mypair._Myval2._Myres >= _Mypair._Myval2._BUF_SIZE">{_Mypair._Myval2._Bx._Ptr,s8}</DisplayString> <StringView Condition="_Mypair._Myval2._Myres < _Mypair._Myval2._BUF_SIZE">_Mypair._Myval2._Bx._Buf,s8</StringView> <StringView Condition="_Mypair._Myval2._Myres >= _Mypair._Myval2._BUF_SIZE">_Mypair._Myval2._Bx._Ptr,s8</StringView>
之后,vs2015即可在debug时正常显示utf-8字符。TODO
还有个帖子说,“只需要将要显示的字符串拉到Watch中,并在变量后面添加,s8即可显示”,经测,这么做是不行的,监视窗口会报错,如下:
c/c++ 语言默认什么编码
C语言是没有编码的。它的编码就是平台的默认编码。
比方说在windows 上汉字编码用gb2312 或者 说cp936(GBK一般的windows默认代码页,windows分为不同的代码页,可以查看一下MSDN)。
http://msdn.microsoft.com/zh-cn/goglobal/cc305153(en-us).aspx
C里char 就是一个字节。你定义一个汉字,比方说 char *p=“中”C语言用两个字节来存储;
p指向的两个字节存储的就是‘中’的gb编码。分别是‘xd6xd0’。
当然如果用printf("%s",p) 输入到屏幕的话,它会自动解码输出‘中’这个字。
如果在linux平台下,一般是uft-8编码的,汉字3个字节,道理一样。
=========
也就是说,默认locale是C,字符集是ascii。
当我们的输入是一组带有中文或者其他字符的字符串时候,他就会截断。只会转化前面的ascii字符。
所以在中文路径下是不能work的。
如果我们存在中文路径,或者字符,想使用wcstombs该函数来将宽字符串转为多字节字符串,那么我们就得设置系统的当前环境的locale.
这里列出使用数组存储 1 个汉字的实例(https://blog.csdn.net/xiaoboliu0602/article/details/109189202)
char a[] = "字"; // 定义一个汉字的数组 char a[] = {"字"}; // 也可以加上 { } 这两种情况系统都会在后面自动加上'\0',即 a[3] = '\0' 汉字占3个字节 a[0]、a[1]和a[2]; 也可以这样: char a[4] = "字"; char a[4] = {"字"}; 以上两种方法定义的空间是一样大的,都是4个字节。 char i; for(i=0;i<4;i++) { printf("a[%d] = 0x%x;\r\n",i,a[i]); } 使用char时output: a[0] = 0xffffffe5; a[1] = 0xffffffad; a[2] = 0xffffff97; a[3] = 0x00; 使用unsigned char时output: a[0] = 0xe5; a[1] = 0xad; a[2] = 0x97; a[3] = 0x00;
========最后一个完整的示例
#include <iostream> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <locale.h> #include <wchar.h> using namespace std; class Object { }; class Person : public Object { public: char ext[32] = {0}; wchar_t* cn_name = NULL; void Print() { // convert char to wchar_t, then print https://cplusplus.com/reference/cstdlib/mbstowcs/ char* pmb = (char*)malloc(32); const wchar_t* pwc = L"Hi中国\0"; wcstombs(pmb, pwc, 31); cout << "name:" << _name << endl; cout << "age:" << _age << endl; printf("ext=%s, ext_size=%d, cn_name=%ls\n", ext == NULL ? "" : ext,strlen(ext), cn_name == NULL ? L"" : cn_name); // ok, 即使有宽字符,printf也已足够 printf("pmb=%s\n", pmb); // ok wprintf(L"cn_name=%ls,pwc=%ls,pmb=%s \n", cn_name, pwc, pmb); // ok, 任何时候在一个文件描述符上,printf/wprintf只能生效一个,另一个会忽略。谁先出现谁生效 // 宽字符依赖于locale明确设置,char数组中文不依赖 } protected: string _name = "peter张"; // 姓名 int _age = 18; // 年龄 }; // Student继承了Person,Student中就拥有了Person的成员 //Person叫父类/基类 //Student叫子类/派生类 class Student : public Person { protected: int _stuid; // 学号 } ; class Teacher : public Person { protected: int _jobid; // 工号 }; int main(int argc, char* argv[]) { // char* loc = setlocale(LC_ALL, "zh_CN.UTF-8"); // printf("loc=%s\n", loc); Student s; Teacher t; Object p1 = t; // t.ext = (char *)malloc(33); // memset((void *)t.ext, 0, 33); strcpy(t.ext, "中国ext name"); t.cn_name = (wchar_t *)malloc(32); memset((void *)t.cn_name, 0, 32); mbstowcs(t.cn_name, "中文扩展名balaba", sizeof("中文扩展名balaba")); t.Print(); s.Print(); printf("from c stdio.h\n"); return 0; }
参考
https://blog.csdn.net/wangsen_sc/article/details/6915995
https://blog.csdn.net/weiwangchao_/article/details/43453053
https://blog.csdn.net/angelxf/article/details/7803495
http://www.cplusplus.com/reference/cstdio/printf/(关键时候看官方手册)
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 上周热点回顾(2.24-3.2)