C++ std::filesystem::path转std::string的编码问题及解决
C++17 filesystem路径处理崩溃与调试乱码问题
问题场景
遍历目录获取文件名时,遇到含特定字符的路径会触发崩溃。使用Visual Studio 2022编译,C标准为C17。
原始代码
#include <filesystem> int main() { const char* dir = "D:\\Music"; std::vector<std::string> musicList; for (const auto& entry : std::filesystem::recursive_directory_iterator(dir)) { if (entry.is_regular_file()) { musicList.emplace_back(entry.path().string()); } } }
崩溃触发情况
处理类似L"D:\\Music\\suki\\Angel Note - 月明かりは優しく・・・.mp3"的路径时,entry.path().string()会触发崩溃,程序终止并指向以下系统库代码:
_STD_BEGIN // We would really love to use the proper way of building error_code by specializing // is_error_code_enum and make_error_code for __std_win_error, but because: // 1. We would like to keep the definition of __std_win_error in xfilesystem_abi.h // 2. and xfilesystem_abi.h cannot include <system_error> // 3. and specialization of is_error_code_enum and overload of make_error_code // need to be kept together with the enum (see limerick in N4950 [temp.expl.spec]/8) // we resort to using this _Make_ec helper. _NODISCARD inline error_code _Make_ec(__std_win_error _Errno) noexcept { // make an error_code return { static_cast<int>(_Errno), _STD system_category() }; } [[noreturn]] inline void _Throw_system_error_from_std_win_error(const __std_win_error _Errno) { _THROW(system_error{ _Make_ec(_Errno) }); // Here occur error! } _STD_END
问题简化排查
将问题简化为以下代码,同样在path.string()处崩溃,确认是字符・(Unicode编码\u30FB)导致的问题:
#include <filesystem> int main() { std::filesystem::path path = L"・"; auto str = path.string(); }
注:path.wstring()、path.u8string()转换均正常,但业务需要char*类型以适配ImGui::Text或FMOD等API。
编码转换的乱码问题
尝试用Win32 API将wstring转为UTF-8编码的string时,调试界面显示乱码(例如得到"・"而非预期的UTF-8编码字节序列),转换代码如下:
#include <filesystem> #include <Windows.h> std::string ws2s(const std::wstring& wstr) { int len = WideCharToMultiByte(CP_UTF8, 0, wstr.c_str(), -1, nullptr, 0, nullptr, nullptr); std::string str; str.reserve(len); WideCharToMultiByte(CP_UTF8, 0, wstr.c_str(), -1, str.data(), len, nullptr, nullptr); return str; } int main() { std::filesystem::path path = L"\u30FB"; auto str = ws2s(path.wstring()); }
问题根源解决
后续发现是Visual Studio调试界面的编码问题导致UTF-8内容显示异常:vector<string>中实际存储的是正确的UTF-8编码内容,仅调试器显示乱码。只需在监视窗口中给变量(如vec[0])追加,s8,即可强制调试器以UTF-8编码解析并正确显示内容。
疑问
微软为何执着于UTF-16?UTF-8难道不够好用吗?
内容的提问来源于stack exchange,提问作者guruguru
相关产品推荐
相关产品推荐

