
static std::wstring format_string(CONST WCHAR* pszText, ...) { std::wstring result; va_list args; va_start(args, pszText); int len = _vscwprintf(pszText, args); if (len < 0) { wprintf_s(L"_vscwprintf failed, len=%i, error=%i\n", len, errno); return L""; } result.resize((size_t)len); vswprintf_s(const_cast<WCHAR*>(result.data()), result.size() + sizeof(WCHAR), pszText, args); va_end(args); return result; } int wmain(int argc, wchar_t* argv[]) { wprintf_s(L"%S\n", setlocale(LC_ALL, ".UTF8")); std::wstring msg = format_string(L"msg: %hs", u8"abc 你好"); wprintf_s(L"msg: %s\n", msg.c_str()); return 0; } 输出: Chinese (Simplified)_China.utf8 _vsctprintf failed, len=-1, error=0 msg: 操作系统:Windows 10 x64
编译器:vs2019, mingw-w64-v8.1.0
项目字符集:UNICODE
项目文件:test_utf8.zip - 蓝奏云
1 missdeer 2021-05-07 09:30:16 +08:00 用 char*试试 |
2 wtfdsy 2021-05-07 09:56:22 +08:00 格式的%hs 换成%s |
3 lonewolfakela 2021-05-07 10:21:24 +08:00 盲猜是 windows 的_vscwprintf 系列函数有 bug,不能正常处理 utf8,不然没法解释为啥 len=-1 但是 errno 却是 0…… 不知道楼主这段代码的需求是怎样的,能不能换别的函数进行处理? |
4 jones2000 2021-05-07 11:12:27 +08:00 %ls 或%s |
5 ysc3839 2021-05-07 13:02:26 +08:00 via Android 印象中 C 里面 wchar 系列函数有坑,会根据当前 locale 进行一些转换的。 Windows 下控制台要输出 Unicode 系列编码的字符串,建议转成 UTF-16 然后用 WriteConsole 输出。 |
6 jayvien OP @lonewolfakela 经过一天的尝试,同意你的猜测,UTF-8 编码的字符串只有多字节系列的函数才能正确处理。原始需求是实现一个日志库,传多参,可以正常处理宽字节( UTF-16LE )和多字节( UTF-8 )的日志参数,并且写出 UTF- 编码的文件。目前已经改成通过多字节系列的函数来实现了,_vscprintf 、vsprintf_s 、printf_s 、fprintf_s,写出文件的时候要用二进制模式,需要 UTF-8 BOM 头的话要自己写"\xEF\xBB\xBF"。 |
7 jayvien OP 需要注意的是,虽然 setlocale 设置了 UTF-8 语言环境,_fsopen 仍然不支持 UTF-8 编码的文件路径,因此需要通过 _wfsopen 打开文件。 |
8 jayvien OP 另外,utf8everywhere 里也有提到一些这方面的技巧,http://utf8everywhere.org/zh-cn |
9 ysc3839 2021-05-07 20:31:47 +08:00 via Android @jayvien 你要在 Windows 下使用 UTF-8 文件路径的话,只能把当前进程的 active code page 设置成 UTF-8 来实现,这个操作印象中从 Win10 某个版本开始才支持。否则你必须转换成 UTF-16 。 Windows 中的 Unicode 使用的是 UTF-16 编码。但是为了兼容性,有一些系统 API 有非 Unicode 的版本,这些非 Unicode 的版本内部一般是使用 active code page 转换成 UTF-16 。 |
10 nvioue 2021-05-08 00:16:21 +08:00 .... 兄弟你是完全不熟悉 Windows 编程吧... 我给你们简单科普一下 windows 凡是跟字符串相关的 api 大部分都有 A 和 W 两个版本 你用的这个 xxxprint 系列函数我个人认为不算是 windows api. 是 VC 运行库函数, 一样的会映射多字节 multibyte 和 unicode 两个版本. 如果你的目的是混合输出 char 和 wchar 的话... 其实这非常奇怪的需求了. 我建议你统一一下 混合输出你必须手动 MultiByteToWideChar 和 WideCharToMultiByte. 没有人会帮你转换的. 你要知道光简体中文都有 , gbk, gb18080.. 至少 3 个编码; 你如果是输出中文需求的话可不要小瞧了这两个函数.. 打日志到文件的话没必要这么麻烦, 我告诉你用上述 api 转换完了之后直接用 WriteFile 写文件完事 |