在Windows上使用C语言清空命令提示符

4

在Windows系统上,使用C语言是否可以清空命令行的输出?

例如,在Linux系统下,可以使用以下命令:

printf("\033[2J");

据我所知,Windows不认识ANSI转义码。谢谢。

编辑:我猜下一个输出前也需要将光标返回到0,0...


1
任何答案都取决于您运行程序的终端环境。您有更多详细信息吗? - Carl Norum
@CarlNorum 普通的Windows(7)命令提示符,即cmd.exe。 - Toby
2个回答

8

在Windows上有很多方法可以做到这一点。

您可以包含conio.h并调用_clrscr();

或者您可以调用system("cls");


_clrscr();clrscr(); - Rustam
FYI,clrscr 在 C++Builder 中可用,但在 VC++ 中不可用(参见http://support.microsoft.com/kb/99261)。 - Eryk Sun

6

作为替代conio.h或系统调用的一种实现(我认为类似于conio库),它展示了在Windows中应该如何完成。

#include <windows.h>

int main(void){
    HANDLE hStdout; 
    CONSOLE_SCREEN_BUFFER_INFO csbiInfo; 
    DWORD dwCells, dwWritten;

    // Get console handle
    hStdout = GetStdHandle(STD_OUTPUT_HANDLE);     

    // Retrieve console information
    if (GetConsoleScreenBufferInfo(hStdout, &csbiInfo)) {

        // Calc console cells
        dwCells = csbiInfo.dwSize.Y * csbiInfo.dwSize.X;

        // Initialize cursor position
        csbiInfo.dwCursorPosition.X = 0;
        csbiInfo.dwCursorPosition.Y = 0;

        // Replace all characters in console with spaces
        FillConsoleOutputCharacterA( hStdout, ' ', dwCells, csbiInfo.dwCursorPosition,  &dwWritten);
        // Replace all attributes in console with the default
        FillConsoleOutputAttribute( hStdout, csbiInfo.wAttributes, dwCells, csbiInfo.dwCursorPosition, &dwWritten );
        // Position the cursor
        SetConsoleCursorPosition( hStdout, csbiInfo.dwCursorPosition );
    }

    return 0;
}

编辑遵循评论

经过一些测试,这大致是在 cmd.exe 中实现 cls 命令的方式(至少在 Windows 7 64 位)

#include <windows.h>

int main(void){
    HANDLE hStdout; 
    CONSOLE_SCREEN_BUFFER_INFO csbiInfo; 
    COORD destinationPoint;
    SMALL_RECT sourceArea;
    CHAR_INFO Fill;

    // Get console handle
    hStdout = GetStdHandle(STD_OUTPUT_HANDLE);     

    // Retrieve console information
    if (GetConsoleScreenBufferInfo(hStdout, &csbiInfo)) {
        // Select all the console buffer as source
        sourceArea.Top = 0;
        sourceArea.Left = 0;
        sourceArea.Bottom = csbiInfo.dwSize.Y - 1;
        sourceArea.Right = csbiInfo.dwSize.X - 1;

        // Select a place out of the console to move the buffer
        destinationPoint.X = 0;
        destinationPoint.Y = 0 - csbiInfo.dwSize.Y;

        // Configure fill character and attributes
        Fill.Char.AsciiChar = ' ';
        Fill.Attributes =  csbiInfo.wAttributes;

        // Move all the information out of the console buffer and init the buffer
        ScrollConsoleScreenBuffer( hStdout, &sourceArea, NULL, destinationPoint, &Fill);

        // Position the cursor
        destinationPoint.X = 0;
        destinationPoint.Y = 0;
        SetConsoleCursorPosition( hStdout, destinationPoint );
    }

    return 0;
}

不是通过调用API函数填充缓冲区所需的字符和属性,而是滚动整个缓冲区,当滚动操作填充空白区域时,初始化缓冲区。这一切都在一个api调用中完成。

编辑 这是等效于ANSI转义序列的代码。清除控制台但保留历史记录。这不会初始化完整的控制台缓冲区,仅确保控制台窗口干净,如果需要,滚动可见窗口或缓冲区。

#include <windows.h>

int main(void){
    HANDLE hStdout; 
    CONSOLE_SCREEN_BUFFER_INFO csbiInfo; 
    COORD destinationPoint;
    SMALL_RECT sourceArea;
    CHAR_INFO Fill;
    SHORT delta, end;

    // Get console handle
    hStdout = GetStdHandle(STD_OUTPUT_HANDLE);     

    // Retrieve console information
    if (GetConsoleScreenBufferInfo(hStdout, &csbiInfo)) {

        // How many lines needs the window to be moved to be clear
        delta = (csbiInfo.dwCursorPosition.Y) - csbiInfo.srWindow.Top;

        // Where the bottom of the window will fall after moving
        end = csbiInfo.srWindow.Bottom + delta;

        // If the window get out of the console buffer, it is necessary to scroll the buffer
        if (end >= csbiInfo.dwSize.Y){
            // Select all the console buffer as source
            sourceArea.Top = 0;
            sourceArea.Left = 0;
            sourceArea.Bottom = csbiInfo.dwSize.Y-1;
            sourceArea.Right = csbiInfo.dwSize.X-1;

            // Select the target point for the movement
            destinationPoint.X = 0;
            destinationPoint.Y = 0 - delta ;

            // Configure fill character and attributes for the empty area
            Fill.Char.AsciiChar = ' ';
            Fill.Attributes =  csbiInfo.wAttributes;

            // Scroll the buffer and init the end zone
            ScrollConsoleScreenBuffer( hStdout, &sourceArea, NULL, destinationPoint, &Fill);

            // Adjust new cursor position
            destinationPoint.X = 0;
            destinationPoint.Y = csbiInfo.dwSize.Y - (csbiInfo.srWindow.Bottom - csbiInfo.srWindow.Top + 1);

        } else {
            // No buffer scroll is needed. Adjust the new cursor position
            destinationPoint.X = 0;
            destinationPoint.Y = csbiInfo.dwCursorPosition.Y + 1;
        }

        // In any case, the visible window needs to be moved depending on the new cursor position
        sourceArea.Top = destinationPoint.Y;
        sourceArea.Left = destinationPoint.X;
        sourceArea.Bottom = destinationPoint.Y + (csbiInfo.srWindow.Bottom - csbiInfo.srWindow.Top + 1) -1 ;
        sourceArea.Right = csbiInfo.dwSize.X-1;

        // Place the visible window in the required place over the buffer
        SetConsoleWindowInfo(hStdout, TRUE, &sourceArea);

        // Place the cursor in its final position
        SetConsoleCursorPosition( hStdout, destinationPoint );
    }

    return 0;
}

cls 命令采用不同的路线。它还获取屏幕缓冲区信息以获取缓冲区大小和填充字符属性。然后,它调用 ScrollConsoleScreenBuffer 将屏幕完全滚动到缓冲区之外,即滚动到目标 (0, 0 - dwSize.Y)。一个更有用的命令(称其为 clear.exe)将使用 srWindow 中的窗口大小仅移动单个显示页面的缓冲区。这将在使用具有(许多)比窗口更多行的屏幕布局时保留输出历史记录。 - Eryk Sun
@eryksun,我已经阅读了它(和文档),但我仍然没有看到需要使用ScrollConsoleScreenBuffer的原因,抱歉,也许我错过了什么。无论如何,重新阅读问题和ansi转义的效果后,我认为你用clear.exe方法是正确的。我手头没有C编译器进行测试,但等我有机会时,我会添加相应的代码。 - MC ND
1
@eryksun,完成了。我已经包含了更接近Microsoft清理控制台的版本,只需一个API调用来清除控制台和一个API调用来定位光标。同时,clear.exe代码也已经包含在内。 - MC ND
这应该是被接受的答案。clear.exe 的作用类似于 Unix 终端中的 clear^J - Eryk Sun

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接