WinAPI建议设为使用Unicode字符集(在工程属性里设置),也就是使用宽字符,然后使用MultiByteToWideChar和WideCharToMultiByte在宽字符和各种字符编码如GBK、UTF-8之间转换,GBK代码页是936,UTF-8代码页是65001。
文本文件建议使用UTF-8编码(字符乱码是非常显著的信号,所以不需要兼容所有字符编码),不过还是要兼容BOM以免Win10之前的用户困惑。
文件建议直接使用CreateFile打开读写,支持Unicode路径名。如遇到第三方库不能使用Unicode或UTF-8路径名,则使用GBK路径名也是可以的。
OpenCV4.0的imgcodecs模块,现在虽然imread/imwrite仍然只支持GBK文件名,但是imdecode/imencode已经重构过,不依赖临时文件了(可能是因为有人反馈Windows临时文件路径也可能包含Unicode字符),也就是说现在可以自己用CreateFile读文件,然后让imdecode解码,或者让imencode编码,然后用CreateFile写文件,这样可以添加Unicode路径名支持。
标准输入输出(stdin,stdout,stderr)建议还是使用GBK,这样的话可以允许用户在不改控制台字符编码的情况下显示字符,也可以正常使用重定向/管道功能。
如果需要显示GBK不能表示的字符,可以生成txt或html文件并打开以显示。如果需要编辑GBK不能表示的字符,可以首先生成一个带UTF-8 BOM的txt文件,再打开编辑并等待用户关闭记事本,即可获取输入。打开文件可以使用ShellExecute、ShellExecuteEx、CreateProcess等函数,也可以简单地用_wsystem、_wspawnlp。
注意系统有好几个虚拟代码页/代码页获取函数,但如果只有中文的话则不建议找麻烦,因为除936以外的代码页都不能正常显示简体中文,没有意义。不要考虑在控制台支持Unicode或UTF-8,微软已经承认这里有问题了,自己找麻烦得不偿失。
也不要学微软使用wprintf,微软使用这个函数的原因可能是英文Windows默认使用的1252代码页和C运行库没有setlocale之前使用的ISO-8859-1编码重合度较高,因此误以为不进行setlocale也能正常工作。使用wprintf要setlocale,这是个破坏兼容性的操作,建议尽量避免使用wprintf,自己转换。
获取函数 | 虚拟代码页 | 简体中文系统 |
典型西文系统 |
含义 |
---|---|---|---|---|
GetACP() | CP_ACP(0) | 936(GBK) | 英1252 俄1251 |
(系统级)ANSI版本WinAPI和C运行库的编码 |
GetOEMCP() | CP_OEMCP(1) | 936 | 英437/850 俄866 |
(系统级)OEM/DOS编码(很少使用) |
GetConsoleCP() | 936 | 英437/850 俄866 |
控制台输入编码,默认与OEM/DOS编码相同 | |
GetConsoleOutputCP() | 936 | 英437/850 俄866 |
控制台输出编码,正常情况下和输入编码相同,默认与OEM/DOS编码相同 | |
CP_UTF8(65001) | 65001 | 65001 | UTF-8 |