clrscr() 不工作,getch() 工作。为什么?

clrscr() not working, getch() working. Why?

我正在制作一个小的 C 程序,它要求输入密钥并在 switch 语句中执行一些代码。

#include <stdio.h>
#include <conio.h>

int main(int argc, char const *argv[]){
    /* code */
    printf("Hello, press a, b or c to continue");
    char key = getch();
    switch (key){
    case  'a':
        clrscr();
        //some code
        break;
    case  'b':
        //many lines of code
        break;
    case  'c':
        clrscr();
        //many lines of code
        break;
    default:
        printf("Ok saliendo\n");
        break;
    }
    printf("bye");
}

getch() 工作正常,但 clrscr() 不是,即使我包含 <conio.h>.

为什么?

conio.h死了!

一些背景:conio.h 定义了一个 API,它曾经被创建用于控制 IBM PC 的(文本!)屏幕。它最初只是 MS-DOS 函数的包装器,因此您不必编写自己的程序集来创建 int 21h 来调用它们。 conio.h 的确切 API 从未标准化,并且因实施而异。

我假设您使用的是针对 Windows 的编译器,这些编译器通常仍会提供 conio.h 的一些变体。但如您所见,无法保证真正可用并按预期工作。

如今,您甚至不得不问 什么是屏幕? 控制台 window 的内容?但是,如果您的控制终端是例如远程 shell(telnet、ssh、...)?甚至不同的 console window 实现在功能和控制方式上也会有所不同。 C 只知道输入和输出 streams,它们可以与任何类型的终端/控制台一起工作,因为它们对 screen 一无所知,只是字符的输入和输出。

为了实际控制"screen",Windows提供了Console API, you could use that directly, but then your program is "hard-wired" to Windows only. Most other consoles / terminals understand some sort of escape codes, often the ANSI escape codes。 Windows 以 Windows 10 开头也有对它们的可选支持。但是有各种各样的终端理解不同的代码(以及它们的不同子集),所以直接使用它们也不是一个好主意。


如今,控制 terminal/console 的 事实上的标准 是实现其 的 Windows 的 Curses API which has its roots in BSD Unix, but implementations exist for a large variety of systems and consoles. Most notably, ncurses is available for many systems, even including Windows, but for Windows, you also have pdcurses. There's even an extended pdcurses拥有 控制台 window,因此您可以使用原生 Windows 控制台没有的功能。当然,您不会仅仅为了 "clearing the screen" 和从键盘读取一些输入而需要它。

当你使用 curses 时,你必须使用 curses 函数完成所有 console/terminal 输入和输出(你不能使用像 [=21] 这样的 stdio 函数=] 为此)。这是一个小示例程序:

#include <curses.h>
// don't include `ncurses.h` here, so this program works with 
// different curses implementations

#include <ctype.h>  // for `isalnum()`

int main(void)
{
    initscr();  // initialize curses, this also "clears" the screen
    cbreak();   // among other things, disable buffering
    noecho();   // disable "echo" of characters from input

    addstr("Hello, press a key!\n");  // output a constant string, like puts/fputs
    refresh();  // output might be buffered, this forces copy to "screen"

    int c;
    do
    {
        c = getch();        // read a single character from keyboard
    } while (!isalnum(c));  // ignore any input that's not alphanumeric

    printw("You entered '%c'.\n", c);  // formatted output, like printf

    addstr("press key to exit.\n");
    refresh();
    c = getch();

    endwin();   // exit curses
}

你可以编译它,例如使用 ncurses:

这样的 gcc
gcc -std=c11 -Wall -Wextra -pedantic -ocursestest cursestest.c -lncurses

pdcurses:

gcc -std=c11 -Wall -Wextra -pedantic -ocursestest cursestest.c -lpdcurses

要了解有关 curses 的更多信息,我推荐 NCURSES Programming HOWTO