同样,使用的是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带签名格式即可。
输出:
最后,宽字符的操作函数和char不同
上述设置后,环境中就是指定的字符集了,但是vs监视窗口仍然会是显示16进制,如下:
将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编码的,汉字三个字节,道理一样。
=========
当C语言程序初始化时(刚进入到 main() 时),locale 被初始化为默认的 C locale,其采用的字符编码是所有本地 ANSI 字符集编码的公共部分,是用来书写C语言源程序的最小字符集(所以才起locale名叫:C)。
也就是说,默认locale是C,字符集是ascii。
当我们的输入是一组带有中文或者其他字符的字符串时候,他就会截断。只会转化前面的ascii字符。
所以在中文路径下是不能work的。
如果我们存在中文路径,或者字符,想使用wcstombs该函数来将宽字符串转为多字节字符串,那么我们就得设置系统的当前环境的locale.
这里列出使用数组存储 1 个汉字的实例
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;
}
参考
http://www.cplusplus.com/reference/cstdio/printf/(关键时候看官方手册)