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 &lt; _Mypair._Myval2._BUF_SIZE">{_Mypair._Myval2._Bx._Buf,s8}</DisplayString>
      <DisplayString Condition="_Mypair._Myval2._Myres &gt;= _Mypair._Myval2._BUF_SIZE">{_Mypair._Myval2._Bx._Ptr,s8}</DisplayString>
      <StringView Condition="_Mypair._Myval2._Myres &lt; _Mypair._Myval2._BUF_SIZE">_Mypair._Myval2._Bx._Buf,s8</StringView>
      <StringView Condition="_Mypair._Myval2._Myres &gt;= _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个字节,道理一样。

  =========

 

 

  当C语言程序初始化时(刚进入到 main() 时),locale 被初始化为默认的 C locale,其采用的字符编码是所有本地 ANSI 字符集编码的公共部分,是用来书写C语言源程序的最小字符集(所以才起locale名叫:C)。
  也就是说,默认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/(关键时候看官方手册)

posted @ 2018-07-10 13:45  zhjh256  阅读(2635)  评论(0编辑  收藏  举报