今天碰到有人在群里问我“C实现清屏是不是只能system(“cls”);或一直换行?”,一时不知道怎么回答,毕竟一般在控制台里清屏,就是用的 system(“cls”)。
system(“cls”) 是调用了 C 标准库函数 system,作用就是将命令传递给控制台去解析执行。那么我们回顾一下命令执行的过程大致如下:会有一个字符串的解析,会尝试搜索外部命令,会与内部命令一一对比,还要看看是否可能加了参数,最后才转入 cls 的执行函数,然后调 API 清屏。
这么一看,它的效率实在不敢恭维。对于一个在速度上要求极高的人,这是不可忍受的。想到 Demon 大神曾对 cmd 进行了一系列分析,写出了个[批处理内幕]系列文章,那么我为什么不分析分析 cls 的背后到底都做了什么呢?
水平有限,如果操作有误还请大家不吝指教。
##准备
调试工具 OllyDbg 吾爱破解专用版,被调试程序 cmd.exe,系统环境:Win7 Ultimate。
推源码,尝试过使用 IDA,然而根本找不到那个地址(后来想到交叉引用,不过那时候我已经推出代码了,故而不再考虑),于是就只能手推了。根据 MSDN 手册作参考,推的过程不细讲,最后得到如下的代码
void clearScreen()
{
HANDLE hStdOut;
CONSOLE_SCREEN_BUFFER_INFO bufInfo;
SMALL_RECT scroll;
COORD newCursorPointer;
CHAR_INFO ciFill;
hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
if(!GetConsoleScreenBufferInfo(hStdOut, &bufInfo))
return;
scroll.Left = 0;
scroll.Top = 0;
scroll.Right = bufInfo.dwSize.X;
scroll.Bottom = bufInfo.dwSize.Y;
newCursorPointer.X = 0;
newCursorPointer.Y = -bufInfo.dwSize.Y;
ciFill.Char.UnicodeChar = L' ';
ciFill.Attributes = bufInfo.wAttributes;
ScrollConsoleScreenBufferW(hStdOut, &scroll, NULL, newCursorPointer, &ciFill);
newCursorPointer.Y = 0;
SetConsoleCursorPosition(hStdOut, newCursorPointer);
}
好了,大功告成。经测试对 200 行的输出,system(“cls”) 所耗费时间大概在 90ms 到 100ms 之间浮动,而同样条件下 clearScreen() 仅 1ms 到 3ms,高下立判。测试代码就不附了。
##结语
终于可以回答那位朋友了,除了 system(“cls”) 以及他说的那种方法以外,还可以用我的 clearScreen() 哦~
另由此引申下,很多朋友喜欢用在一个程序中调用另一个程序,不过一个小小的 system(“cls”) 都要花费那么多的时间,调用其他进程的损耗不知道多少?因此能在这个程序里实现最好,尽量少调用外部程序。
为了写这篇文章还特地回去翻了翻 Demon 大神的一篇博文,批处理技术内幕:ECHO 命令,里面有说到控制台解析命令时的大致过程。虽然本文中并没有用到多少。曾记得 Demon 大神好像有一篇文章对 cmd 命令搜索过程做了详细的分析,不过这次没找到,以后看看补上吧。