如何显示utf-8编码的字符串?

时间:2023-01-06 21:16:23
在mfc中,建立了一个对话框程序,在这个程序中我加了一个 Static Text控件,我想在这个控制里显示utf-8编码的字符串,可示我发现setwindowtext()只能显示gbk的字符串

1、windows下的程序是什么编码的?比如说可不可能把这个程序直接编译成utf-8的程序,这样传进去的utf-8字符串不就能正常1显示了?
2、如何进行编码的转换?在linux下面,有iconv这个东西,转换编码很方便,windows下面呢?

17 个解决方案

#1


你查一下这个函数MultiByteToWideChar,转换时把第一个参数设置成CP_UTF8就可以了

#2


晕,在工程的属性里面是可以设置使用的字符的,如果你需要使用到多种语言,你应该从一开始开发这个程序就使用Unicode的!

好像在哪里设置使用Unicode也是能够选择utf-8的!自己找一找就见的了!

#3


VC和Windows内部用的Unicode是UTF-16L。你需要按1楼那样转换成UTF-16L。
MFC里给控件显示文字的标准方法是在类向导(第二页)里给Static对象绑定一个CString对(比如m_txtData)。
直接给这个CString对象赋值,然后UpdateData(FALSE);
比如

.....
int utf16size = 0;
int retval = MultiByteToWideChar(CP_UTF8, 0, utf8data, utf8size, NULL, &utf16size);
if (retval == ERROR_INSUFFICIENT_BUFFER) {
    byte *utf16data = new byte[utf16size];
    MultiByteToWideChar(CP_UTF8, 0, utf8data, utf8size, &utf16data, &utf16size);
}
.....
CStringW strTemp((LPCWSTR) utf16data);
delete []utf16data;
m_txtData = strTemp;
UpdateData(FALSE);

如果你的工程只有Unicode,可以不用另外strTemp,直接(LPCWSTR) utf16data给m_txtData赋值就行了。




#4


错了一句byte *utf16data = NULL,应该在前面。否则就超出作用域了

#5


唔,写得太急了,有个大bug

.....
int utf16size = 0;
wchar_t *utf16data = NULL;
int retval = MultiByteToWideChar(CP_UTF8, 0, utf8data, utf8size, NULL, &utf16size);
if (retval == ERROR_INSUFFICIENT_BUFFER) {
    utf16data = new wchar_t[utf16size];
    MultiByteToWideChar(CP_UTF8, 0, utf8data, utf8size, &utf16data, &utf16size);
}
.....
CStringW strTemp((LPCWSTR) utf16data);
delete []utf16data;

m_txtData = strTemp;
UpdateData(FALSE);

#6


楼上的好像还是不太对吧。第一个MultiByteToWideChar最后个参数貌似要是0.
If the function succeeds and cchWideChar is zero, the return value is the required size, in wide characters, for a buffer that can receive the translated string. 

#7


ANSII,UTF-8,UNICODE是一类概念,不要与GBK,GB2132,BIG5这类概念混在一起

#9


用iconv吧,解决一切编码问题
libiconv字符集转换库使用方法

#10


引用 7 楼 llxxhm 的回复:
ANSII,UTF-8,UNICODE是一类概念,不要与GBK,GB2132,BIG5这类概念混在一起


如何理解呢?

#11


引用 3 楼 bokutake 的回复:
VC和Windows内部用的Unicode是UTF-16L。你需要按1楼那样转换成UTF-16L。
MFC里给控件显示文字的标准方法是在类向导(第二页)里给Static对象绑定一个CString对(比如m_txtData)。
直接给这个CString对象赋值,然后UpdateData(FALSE);


也就是说,最终windows只能显示UTF-16L的字符串,我们Static的字符串,它都是以UTF-16L理解的。
用了一个 setwindowtext("程序")的字符串,我把程序源文件保存为gb2312, 然后编译,发现能正常显示;我把源文件保存为utf-8,然后编译,显示为三个乱码字符。这说明了上面的一些问题。但现在我有又些疑问:
如果windows只认UTF-16L,那么gb2312编码的文件编译后也可能是两个字符的乱码,我的猜想:情况1、gb2312和utf-16L对中文字符的编码是一样的,这样就能正常显示gb2312的文字我也可以理解;情况2:windows对setwindowtext("程序")里的两个字符做了转码,因为我用的是中文系统,所以windows(或许是编译器)根据代码业把"程序"两个字符转成了UTF-16L,然后能正常显示。以上两种情况我未去做验证,请高人指点。
那现在源文件保存为utf-8编码格式,编译器编译的时候其实没有理会这源文件是什么编码格式?只是把"程序"两个字符串当作gb2312编码?

#12


引用 6 楼 dahaii0 的回复:
楼上的好像还是不太对吧。第一个MultiByteToWideChar最后个参数貌似要是0.
If the function succeeds and cchWideChar is zero, the return value is the required size, in wide characters, for a buffer that can receive the translate……

嗯,的确用错了,我把它当SetupDi类的函数用了。我以为是第一次调用用参数返回长度。
昨天快睡觉了,没看出来,真是不好意思。

.....
int utf16size = 0;
wchar_t *utf16data = NULL;
int utf16size = MultiByteToWideChar(CP_UTF8, 0, utf8data, utf8size, NULL, 0);
if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
    utf16data = new wchar_t[utf16size];
    MultiByteToWideChar(CP_UTF8, 0, utf8data, utf8size, &utf16data, utf16size);
}
.....
CStringW strTemp((LPCWSTR) utf16data);
delete []utf16data;

m_txtData = strTemp;
UpdateData(FALSE);

#13


嗯,VS2008以后的编译器才支持UTF-8的源代码吧,而且必须有BOM。
对于Unicode工程最好用UTF-8编码(也能用ANSI编码,以前都是ANSI的)源文件。
ANSI工程一般用GBK之类的编码的源文件。
不过这只是编译器解释代码的方式,所以源代码是什么格式并不影响生成的生成EXE是Unicode还是ANSI程序。
最关键的还是你在工程配置里选择的是Unicode和ANSI工程,Unicode工程编译的程序用的是Unicode版的API。所以Unicode程序里应该
SetWindowText(L"程序");或SetWindowText(_T("程序"));
单纯把源代码保存为UTF-8并不影响编译成什么。

#14


ANSI在Windows里其实是错误的一个名词,其实微软内部也经常误用。因为对于某些美国程序员来说,世界上只有ANSI或Windows两种编码。ANSI本来是美国的国家标准,其实就是ISO 8851-1,所以到其它语言环境里这个词其实指的是本地编码。比如GB2132、Big-5等等。

#15


引用 13 楼 bokutake 的回复:
嗯,VS2008以后的编译器才支持UTF-8的源代码吧,而且必须有BOM。
对于Unicode工程最好用UTF-8编码(也能用ANSI编码,以前都是ANSI的)源文件。
ANSI工程一般用GBK之类的编码的源文件。
不过这只是编译器解释代码的方式,所以源代码是什么格式并不影响生成的生成EXE是Unicode还是ANSI程序。
最关键的还是你在工程配置里选择的是Unicode和ANSI工程,……

这下让我有些明白了,源文件跟程序没有什么联系,但是源文件中非英文字符在不同编码下还是有区别的吧。这样的话,程序中最好就不要有非英语字符了。
看了一天多的资料,发现我们这些新人容易把文件编码与程序联系起来,而现在的资料都是直接讲宽字符和ANSI的区别和使用...
谢谢这位大虾的指点。

#16


因为你的程序是SetWindowText("程序");所以生成的是ANSI程序。
编译器把源文件里的字符串转换为ANSI编码(注意这个过程,较早编译器可能无法识别UTF-8格式的源代码),并写入二进制文件里。只有Unicode程序的二进制文件里有Unicode编码的字符串。
对于ANSI程序,调用SetWindowText其实调用的SetWindowTextA,NT内核的系统内部是UTF-16L的,所以有一个转换层再把字符串转换成Unicode,再调用SetWindowTextW。
对于Unicode程序,直接调用SetWindowTextW

#17


windows程序现在都是UNICODE-UTF16,如果你的程序里面有不是UTF16的,比如UTF8,会进行自动转换
在VS中,项目-属性-配置属性-常规-字符集,选择多字符集就可以使现在工程的所有类和控件都支持UTF8了,而不是UTF16.
编码转换可以用
MultiByteToWideChar (CP_ACP, 0, char*, -1, wchar*, wchar*缓冲区大小);

WideCharToMultiByte(CP_ACP,WC_COMPOSITECHECK,TCHAR*,-1,char*,char*缓冲大小,NULL,NULL);

不过只能在WINDOWS默认语言(安装的时候选择的那个,不是控制面板里面的)是中文的时候才能使用,

#1


你查一下这个函数MultiByteToWideChar,转换时把第一个参数设置成CP_UTF8就可以了

#2


晕,在工程的属性里面是可以设置使用的字符的,如果你需要使用到多种语言,你应该从一开始开发这个程序就使用Unicode的!

好像在哪里设置使用Unicode也是能够选择utf-8的!自己找一找就见的了!

#3


VC和Windows内部用的Unicode是UTF-16L。你需要按1楼那样转换成UTF-16L。
MFC里给控件显示文字的标准方法是在类向导(第二页)里给Static对象绑定一个CString对(比如m_txtData)。
直接给这个CString对象赋值,然后UpdateData(FALSE);
比如

.....
int utf16size = 0;
int retval = MultiByteToWideChar(CP_UTF8, 0, utf8data, utf8size, NULL, &utf16size);
if (retval == ERROR_INSUFFICIENT_BUFFER) {
    byte *utf16data = new byte[utf16size];
    MultiByteToWideChar(CP_UTF8, 0, utf8data, utf8size, &utf16data, &utf16size);
}
.....
CStringW strTemp((LPCWSTR) utf16data);
delete []utf16data;
m_txtData = strTemp;
UpdateData(FALSE);

如果你的工程只有Unicode,可以不用另外strTemp,直接(LPCWSTR) utf16data给m_txtData赋值就行了。




#4


错了一句byte *utf16data = NULL,应该在前面。否则就超出作用域了

#5


唔,写得太急了,有个大bug

.....
int utf16size = 0;
wchar_t *utf16data = NULL;
int retval = MultiByteToWideChar(CP_UTF8, 0, utf8data, utf8size, NULL, &utf16size);
if (retval == ERROR_INSUFFICIENT_BUFFER) {
    utf16data = new wchar_t[utf16size];
    MultiByteToWideChar(CP_UTF8, 0, utf8data, utf8size, &utf16data, &utf16size);
}
.....
CStringW strTemp((LPCWSTR) utf16data);
delete []utf16data;

m_txtData = strTemp;
UpdateData(FALSE);

#6


楼上的好像还是不太对吧。第一个MultiByteToWideChar最后个参数貌似要是0.
If the function succeeds and cchWideChar is zero, the return value is the required size, in wide characters, for a buffer that can receive the translated string. 

#7


ANSII,UTF-8,UNICODE是一类概念,不要与GBK,GB2132,BIG5这类概念混在一起

#8


#9


用iconv吧,解决一切编码问题
libiconv字符集转换库使用方法

#10


引用 7 楼 llxxhm 的回复:
ANSII,UTF-8,UNICODE是一类概念,不要与GBK,GB2132,BIG5这类概念混在一起


如何理解呢?

#11


引用 3 楼 bokutake 的回复:
VC和Windows内部用的Unicode是UTF-16L。你需要按1楼那样转换成UTF-16L。
MFC里给控件显示文字的标准方法是在类向导(第二页)里给Static对象绑定一个CString对(比如m_txtData)。
直接给这个CString对象赋值,然后UpdateData(FALSE);


也就是说,最终windows只能显示UTF-16L的字符串,我们Static的字符串,它都是以UTF-16L理解的。
用了一个 setwindowtext("程序")的字符串,我把程序源文件保存为gb2312, 然后编译,发现能正常显示;我把源文件保存为utf-8,然后编译,显示为三个乱码字符。这说明了上面的一些问题。但现在我有又些疑问:
如果windows只认UTF-16L,那么gb2312编码的文件编译后也可能是两个字符的乱码,我的猜想:情况1、gb2312和utf-16L对中文字符的编码是一样的,这样就能正常显示gb2312的文字我也可以理解;情况2:windows对setwindowtext("程序")里的两个字符做了转码,因为我用的是中文系统,所以windows(或许是编译器)根据代码业把"程序"两个字符转成了UTF-16L,然后能正常显示。以上两种情况我未去做验证,请高人指点。
那现在源文件保存为utf-8编码格式,编译器编译的时候其实没有理会这源文件是什么编码格式?只是把"程序"两个字符串当作gb2312编码?

#12


引用 6 楼 dahaii0 的回复:
楼上的好像还是不太对吧。第一个MultiByteToWideChar最后个参数貌似要是0.
If the function succeeds and cchWideChar is zero, the return value is the required size, in wide characters, for a buffer that can receive the translate……

嗯,的确用错了,我把它当SetupDi类的函数用了。我以为是第一次调用用参数返回长度。
昨天快睡觉了,没看出来,真是不好意思。

.....
int utf16size = 0;
wchar_t *utf16data = NULL;
int utf16size = MultiByteToWideChar(CP_UTF8, 0, utf8data, utf8size, NULL, 0);
if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
    utf16data = new wchar_t[utf16size];
    MultiByteToWideChar(CP_UTF8, 0, utf8data, utf8size, &utf16data, utf16size);
}
.....
CStringW strTemp((LPCWSTR) utf16data);
delete []utf16data;

m_txtData = strTemp;
UpdateData(FALSE);

#13


嗯,VS2008以后的编译器才支持UTF-8的源代码吧,而且必须有BOM。
对于Unicode工程最好用UTF-8编码(也能用ANSI编码,以前都是ANSI的)源文件。
ANSI工程一般用GBK之类的编码的源文件。
不过这只是编译器解释代码的方式,所以源代码是什么格式并不影响生成的生成EXE是Unicode还是ANSI程序。
最关键的还是你在工程配置里选择的是Unicode和ANSI工程,Unicode工程编译的程序用的是Unicode版的API。所以Unicode程序里应该
SetWindowText(L"程序");或SetWindowText(_T("程序"));
单纯把源代码保存为UTF-8并不影响编译成什么。

#14


ANSI在Windows里其实是错误的一个名词,其实微软内部也经常误用。因为对于某些美国程序员来说,世界上只有ANSI或Windows两种编码。ANSI本来是美国的国家标准,其实就是ISO 8851-1,所以到其它语言环境里这个词其实指的是本地编码。比如GB2132、Big-5等等。

#15


引用 13 楼 bokutake 的回复:
嗯,VS2008以后的编译器才支持UTF-8的源代码吧,而且必须有BOM。
对于Unicode工程最好用UTF-8编码(也能用ANSI编码,以前都是ANSI的)源文件。
ANSI工程一般用GBK之类的编码的源文件。
不过这只是编译器解释代码的方式,所以源代码是什么格式并不影响生成的生成EXE是Unicode还是ANSI程序。
最关键的还是你在工程配置里选择的是Unicode和ANSI工程,……

这下让我有些明白了,源文件跟程序没有什么联系,但是源文件中非英文字符在不同编码下还是有区别的吧。这样的话,程序中最好就不要有非英语字符了。
看了一天多的资料,发现我们这些新人容易把文件编码与程序联系起来,而现在的资料都是直接讲宽字符和ANSI的区别和使用...
谢谢这位大虾的指点。

#16


因为你的程序是SetWindowText("程序");所以生成的是ANSI程序。
编译器把源文件里的字符串转换为ANSI编码(注意这个过程,较早编译器可能无法识别UTF-8格式的源代码),并写入二进制文件里。只有Unicode程序的二进制文件里有Unicode编码的字符串。
对于ANSI程序,调用SetWindowText其实调用的SetWindowTextA,NT内核的系统内部是UTF-16L的,所以有一个转换层再把字符串转换成Unicode,再调用SetWindowTextW。
对于Unicode程序,直接调用SetWindowTextW

#17


windows程序现在都是UNICODE-UTF16,如果你的程序里面有不是UTF16的,比如UTF8,会进行自动转换
在VS中,项目-属性-配置属性-常规-字符集,选择多字符集就可以使现在工程的所有类和控件都支持UTF8了,而不是UTF16.
编码转换可以用
MultiByteToWideChar (CP_ACP, 0, char*, -1, wchar*, wchar*缓冲区大小);

WideCharToMultiByte(CP_ACP,WC_COMPOSITECHECK,TCHAR*,-1,char*,char*缓冲大小,NULL,NULL);

不过只能在WINDOWS默认语言(安装的时候选择的那个,不是控制面板里面的)是中文的时候才能使用,