Windows Cpp 编程中的几个问题
几个最常见的坑,专门为了处理 Windows 的几个麻烦问题。
关于 scanf 警告不安全
scanf 这一类标准库的函数被微软的 MSVC 编译器视作不安全的,可能有缓冲区溢出的危险,它总是不厌其烦地建议替换为 scanf_s。通常我们不想理会这个建议,可以使用下面的选项
1 |
这里我们进行了冗余的设置,#pragma
选项和下面的_CRT_SECURE_NO_WARNINGS
宏定义都可以用来关闭这些警告,相当于加了两道保险。
输出中文乱码
如果源文件采用 utf-8,在 Windows
尝试进行中文输出,那么我们很可能遇到中文乱码的情况,原因是活动代码页是默认的
GBK 编码而非
utf-8。我们可以手动执行chcp 65001
更改活动代码页为
utf-8,但这个做法不仅麻烦,而且程序执行时有时会打开一个新的界面,导致我们来不急在程序启动之前修改活动代码页。
我们可以利用全局变量的初始化,在 main 函数之前自动先将活动代码页改为 UTF-8:
1 |
|
至于 C++程序输入中文有乱码或者压根无法输入,这个暂时还不会。在 shell/cmd 使用中文输入总有种不太合适的感觉,可能需要使用 GUI 程序,在图形化界面上处理非 ASCII 编码的输入才更加自然,例如 QT 对这些编码问题可以很方便地处理。
对于 Windows 的控制台输出,还有一种做法(参考 fmt 库)是首先判定是否是控制台,然后对于 Windows 控制台,将 utf8 代码转换为 utf16,通过 Windows 提供的
WriteConsoleW
接口直接输出,绕过了std::cout
。
除此之外,c++提供的std::locale
通常也可以保证输出中文正常,例如
1
2
3
4
5
6
7
8
9
int main() {
std::locale::global(std::locale("zh_CN.UTF-8"));
std::cout << "你好\n";
return 0;
}
但是测试发现,它依旧无法保证输入中文正常。
控制台输出颜色
在 Linux 的
shell,我们可以很方便地使用\x1b[94m
等控制字符去调整输出内容的颜色,例如下面的代码只有中间一行会输出蓝色。
1 | std::cout << "no color\n" |
但是这些在 Windows 上默认不支持(测试发现 Windows terminal 会支持,原始的 cmd 和 powershell 不支持)
Windows
环境下可以手动开启一个选项:支持控制台虚拟终端序列,也就是\x1b[94m
等字符,此时就可以正常显示颜色,但是
Windows 为了历史兼容性,并没有默认开启这个选项!(参考微软官方文档)
我们可以利用全局变量的初始化,在 main 函数之前自动开启这个选项:
1 |
|
关于 windows.h 的坑
一个著名的关于 windows.h 这个重要头文件的坑,它自己定义了 min 和 max 这两个宏!这直接与 std::min 和 std::max 冲突了,例如下面的代码可能会先进行宏展开,从而导致编译报错。
1 | a = std::max(b,c); |
一个做法是关闭这两个宏,在导入 windows.h 时使用下面的形式
1 |
另一个做法是加括号,括号也会阻止宏的展开
1 | a = (std::max)(b,c); |
头文件参考
以上的几个小技巧可以进行更完整的封装,具体的头文件windows_console.hpp
存放在Github仓库:Allay。