关于Qt字符集相关的问题讨论
最近在用Qt打开文件时发生了一些有意思的问题,故在此记录。
最近,笔者使用Qt打开文件,出现这么一个现象,无法打开中文路径的文件。在定位后发现源头是在第三方库底层的open时发生了错误,提示“No such file or directory”。而上层则是使用了memcpy(char[1024], QString().toStdString().c_str(), QString().size())。
很快,笔者就想到了是因为字符集的问题。事实上,如果你是使用的Qt提供的操作文件的类型并不会遇到这个问题,比如QFile类型等。但是,如果你使用到第三方库,且遇到中文,则常常会发生这种问题。究其原因是因为Qt默认使用Unicode字符集,而windows中文系统和macOS中文系统使用的是GB2312字符集。
很快,笔者就用QString().toLocal8Bit().data()替换了QString().toStdString().c_str()。
当然,如果你觉得到这就结束了,那可还是too young too simple(ps:跟笔者一样)。
在完成上述的字符集转换操作后仍然无法解决问题,笔者百思不得其解,甚至一度怀疑不是字符集的问题。
后来,在群友点醒之下,使用了strcpy替换了memcpy后,问题竟然奇迹般解决了。这个时候我便开始思考为什么了,strcpy和memcpy的区别是什么。
主要有三大区别:
- strcpy只适用于以 '\0' 结束的字符串,而memcpy适用于任何类型的拷贝。strcpy会拷贝字符串的 '\0' 结束符。
- strcpy不需要指定拷贝长度,遇到 '\0' 会结束拷贝,所以容易出现溢出问题。而memcpy则需要指定拷贝字节长度。
- 通常复制字符串时用strcpy或strncpy,而需要复制其他类型数据时则一般用memcpy。
在一番思索之后,我怀疑问题出现在 '\0' 上,也就是使用memcpy后没有手动添加 '\0' 导致open方法无法识别字符串。
然而事实证明并非如此,并且前面所提到的,问题是出现在中文路径上,也就是说英文路径在整个流程中是正常运行的,因为事实上笔者在调用memcpy之前已经有调用memset了,是可以不需要手动添加 '\0'结束符的。
那这两者的区别还有什么呢,使用strcpy不需要指定长度,那问题是不是就出现在这个长度上了呢。
事实上,笔者调用toLocal8Bit后,memcpy的参数三并没有跟着修改成转换后的结果QByteArray的长度,仍然使用着一开始的QString的长度。在分别输出这两者的长度,一切都明了了。在转换后,其长度发生了变换,且QByteArray的长度大于QString的,因此在拷贝这一环节没有发生溢出,但实际上拷贝不完全。(后面笔者单独输出了中文字符串的QString、toStdString、toLocal8Bit的长度,发现都不相同)。
总结:
问题的根源还是在字符集上,因此在Qt的开发过程中,我们还是得稍微重视这个问题,如果你涉及路径问题。
其次是,同一串字符串,不同字符集的长度问题。
最后,是一些可能会被忽略的问题,比如QByteArray().data()的返回值是一个右值,比如strcpy容易出现溢出问题,更推荐strncpy。
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
2022-03-06 C++11的一些新特性