gtk字符编码问题

⌚Time: 2025-01-23 13:41:00

👨‍💻Author: Jack Ge

在用gtk程序处理汉字字符遇到很多问题。一开始只要有中文字符,要么是显示不了,乱码,要么就是崩溃,闪退,控制台输出一堆警告。全都是字符编码的问题。这几天纠结这些情况,逐渐搞明白了原因。

首先windows系统 API通常有两类,一类是W结尾一类是A结尾的。两者的区别是

A函数是ANSI(美国国家标准学会)字符集的API,而W函数是宽字符集的API。

A函数的API使用的是单字节字符集,这意味着它只能处理ASCII字符(0-127)。这些API函数使用char类型的参数,例如char *或LPSTR等。A函数在很多年前就开始使用了,因此在一些旧的Windows应用程序中仍然可以找到它们的使用。

W函数的API使用的是Unicode字符集,这使得它可以处理更多的字符,包括国际字符和特殊字符。这些API函数使用的是wchar_t类型的参数,例如wchar_t *或LPWSTR等。W函数的API函数在Windows NT系列操作系统中引入,并逐渐取代了A函数的API函数。

如果在使用A函数时传递了非ASCII字符(例如中文字符),可能会导致乱码或无法正常工作。因此,建议在现代的Windows应用程序中尽可能使用W函数,以确保对所有字符的正确处理。

所以对于同时使用windows api和gtk的程序,应该做到下面的两条:

  1. 以A结尾的函数api处理的字符都是ansi编码的。而gtk使用的是utf8编码字符。例如使用FindFirstFileA这种api获取到的文件路径。gtk程序不能直接使用。需要转换成utf8字符后才能在gtk的控件上正常显示。

  2. 从gtk控件所获取到的字符也是utf8格式的编码,需要转换成ansi格式编码之后再对windows系统A字辈的api进行使用。否则就会出错

另外的问题一:

我在使用时遇到一个错误,用std::string储存了一个windowsapi获取的文件路径。一个std::string储存了gtk部件获取的目录。想要对其进行去除路径前缀操作,直接使用出现了问题,获取到的字符去除了过多的前缀。

//filePath 是windows api获取的文件路径
//selDirPath 是gtk目录选择按钮获取的目录路径
std::string filePathNoPrefix = filePath.substr(selDirPath.length());

解决办法是转换成相同的字符编码之后再使用这个办法去除前缀。

另外的问题二:

g_locale_to_utf8可以将本地字符也就是ansi格式的转换成utf8编码格式。但是如果本来就是utf8格式就不能使用。比如我之前保存到sqlite数据库的字符是ansi格式,在tksqlite里面中文是乱码的,而gtk程序在读取后通过g_locale_to_utf8转换后能够正常读取。之后修改用utf8格式的字符储存到数据库,tksqlite能正常显示中文。而gtk程序运行后崩溃,原因是之前就使用g_locale_to_utf8来转换读取到的文字。而现在执行转换就会崩溃。

如何知道程序使用的字符编码

有一个办法知道gtk程序用的中文字符串是什么编码,如果用std::cout在控制台输出是乱码,用g_print打印字符输出是正常的中文文本。说明中文文本就是utf8编码。相反的情况就是ansi编码。而g_print就会提示[invalid utf8 character]之类的。