Windows下如何将C++17 filesystem::path转换为const char*?
优雅解决Windows下C++17 experimental filesystem路径转const char*的问题
我来帮你搞定这个VS2017 Windows平台下的路径转换问题——原来用固定数组加wcstombs的写法确实有缓冲区溢出、需要禁用安全警告的麻烦,这里有两个更安全优雅的方案:
方案一:用标准库安全转换宽/窄字符串
如果必须要得到const char*,可以借助C++标准库的std::wstring_convert和std::codecvt_utf8_utf16来完成宽字符串到窄字符串的转换,用std::string自动管理内存,完全避免手动缓冲区的问题:
#include <locale> #include <codecvt> // 替换循环里的转换代码 std::wstring wide_path = p.path().wstring(); std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> converter; std::string narrow_path = converter.to_bytes(wide_path); auto image = SDL_LoadBMP(narrow_path.c_str());
这个写法不需要定义_CRT_SECURE_NO_WARNINGS,内存由std::string自动释放,也不会出现缓冲区不够用的情况。
方案二:直接用SDL的宽字符版本函数(更推荐)
其实SDL早就考虑到了宽字符路径的场景,提供了SDL_LoadBMPW这个宽字符版本的加载函数,它直接接受const wchar_t*参数——这意味着你完全不需要做任何字符串转换,一步到位:
// 直接调用宽字符版本,省掉转换步骤 auto image = SDL_LoadBMPW(p.path().c_str());
这绝对是最优解:既避免了编码转换可能带来的乱码或错误,又让代码更简洁高效,完美适配Windows原生的宽字符路径机制。
修改后的完整测试代码
下面是用方案二优化后的完整代码,去掉了所有不安全的转换逻辑:
#include <SDL.h> #include <vector> #include <filesystem> namespace fs = std::experimental::filesystem; int main(int argc, char* argv[]) { SDL_Init(SDL_INIT_EVERYTHING); auto window = SDL_CreateWindow("Test", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 800, 400, SDL_WINDOW_SHOWN); auto screenSurface = SDL_GetWindowSurface(window); auto images = std::vector<SDL_Surface*>(); for (auto& p : fs::directory_iterator("media")) { // 直接使用宽字符版本加载函数 auto image = SDL_LoadBMPW(p.path().c_str()); images.push_back(image); } for (auto& image : images) { SDL_BlitSurface(image, NULL, screenSurface, NULL); SDL_UpdateWindowSurface(window); SDL_Delay(2000); } for (auto& image : images) SDL_FreeSurface(image); SDL_DestroyWindow(window); SDL_Quit(); return 0; }
补充说明
- 如果你调用的第三方函数确实没有宽字符版本,方案一的标准库转换方式是最可靠的替代方案,比手动操作
wcstombs安全得多。 - VS2017里的
std::experimental::filesystem在Windows下默认用wchar_t作为路径的字符类型,这是符合C++标准的设计,因为Windows原生路径采用UTF-16编码。
内容的提问来源于stack exchange,提问作者Johannes
相关产品推荐
相关产品推荐

