关于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的区别是什么。

  主要有三大区别:

    1. strcpy只适用于以 '\0' 结束的字符串,而memcpy适用于任何类型的拷贝。strcpy会拷贝字符串的 '\0' 结束符。
    2. strcpy不需要指定拷贝长度,遇到 '\0' 会结束拷贝,所以容易出现溢出问题。而memcpy则需要指定拷贝字节长度。
    3. 通常复制字符串时用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。

posted @ 2023-03-06 22:58  幻cat  阅读(116)  评论(0编辑  收藏  举报