如何使getchar()函数保持退格

时间:2018-05-10 05:38:58

标签: c

#include<stdio.h>
int main(void)
{
    int c;
    while((c=getchar())!=EOF)
    {
        if(c==8)       // 8 is ASCII value of backspace
          printf("\\b");
    }
}

现在我想输入退格并希望getchar()函数将退格的ASCII返回到c(int变量)

注意 - 我不是在询问getch函数我知道getch命令能够读取退格 我只想知道getchar是否能够读取退格 如果是,怎么样?

怎么做请解释我 我是C编程的新手

1 个答案:

答案 0 :(得分:2)

如果您的系统支持POSIX.1-2001中标准化的termios,那么您可以操作标准输入终端以不缓冲您的输入。请考虑以下示例:

#define  _POSIX_C_SOURCE  200809L
#include <stdlib.h>
#include <unistd.h>
#include <termios.h>
#include <signal.h>
#include <string.h>
#include <stdio.h>
#include <errno.h>

/* SIGINT handler */

static volatile sig_atomic_t  done = 0;

static void handle_done(int signum)
{
    if (!done)
        done = signum;
}

static int install_done(const int signum)
{
    struct sigaction  act;
    memset(&act, 0, sizeof act);
    sigemptyset(&act.sa_mask);
    act.sa_handler = handle_done;
    act.sa_flags = 0;
    if (sigaction(signum, &act, NULL) == -1)
        return errno;
    return 0;
}

/* Reverting terminal back to original settings */

static struct termios  terminal_config;

static void revert_terminal(void)
{
    tcsetattr(STDIN_FILENO, TCSAFLUSH, &terminal_config);
}


int main(void)
{
    int  c;

    /* Set up INT (Ctrl+C), TERM, and HUP signal handlers. */
    if (install_done(SIGINT) ||
        install_done(SIGTERM) ||
        install_done(SIGHUP)) {
        fprintf(stderr, "Cannot install signal handlers: %s.\n", strerror(errno));
        return EXIT_FAILURE;
    }

    /* Make terminal input noncanonical; not line buffered. Also disable echo. */
    if (isatty(STDIN_FILENO)) {
        struct termios  config;
        if (tcgetattr(STDIN_FILENO, &terminal_config) == 0 &&
            tcgetattr(STDIN_FILENO, &config) == 0) {
            config.c_lflag &= ~(ICANON | ECHO);
            config.c_cc[VMIN] = 1; /* Blocking input */
            config.c_cc[VTIME] = 0;
            tcsetattr(STDIN_FILENO, TCSANOW, &config);
            atexit(revert_terminal);
        }
    }

    /* Set standard input unbuffered. */
    setvbuf(stdin, NULL, _IONBF, 0);

    printf("Press Ctrl+C to exit.\n");
    fflush(stdout);

    while (!done) {
        c = fgetc(stdin);
        if (c == EOF)
            printf("Read EOF%s\n", ferror(stdin) ? " as an error occurred" : "");
        else
            printf("Read %d = 0x%02x\n", c, (unsigned int)c);
        fflush(stdout);
    }

    return EXIT_SUCCESS;
}

#define行告诉您的C库头文件为基于GNU的系统公开POSIX.1功能。

只要收到INT( Ctrl + C ),TERM或HUP信号,就会设置done标志。 (如果断开与终端的连接,则会发送HUP信号,例如关闭终端窗口。)

terminal_config结构将包含注册为退出函数的revert_terminal()使用的原始终端设置,以将终端设置恢复为在程序启动时读取的原始设置。

如果标准输入是终端,则函数isatty(STDIN_FILENO)返回1。如果是这样,我们获取当前终端设置,并将其修改为非规范模式,并询问每个读取块,直到至少读取一个字符。 (如果设置.c_cc[VMIN]=0.c_cc[VTIME]=0,I / O函数往往会有点混乱,因此如果没有输入待处理,fgetc()返回0.通常它看起来像EOF到stdio.h I / O函数。)

接下来,我们使用setvbuf()告诉C库不要在内部缓冲标准输入。通常,C库使用输入缓冲区进行标准输入,以提高效率。但是,对我们来说,这意味着C库会缓冲输入的字符,我们的程序在输入时可能不会立即看到它们。

类似地,标准输出也被缓冲以提高效率。 C库应该将所有完整的行刷新到实际的标准输出,但是我们可以使用fflush(stdout)调用来确保我们写入stdout的所有内容都被刷新到那时的实际标准输出。

main()中,我们有一个简单的循环,它读取按键,并以十进制和十六进制打印它们。

请注意,当输入信号时,例如INT信号,因为您输入了 Ctrl + C ,信号传递到我们的handle_done()信号如果有一个挂起,处理程序会中断fgetc()调用。这就是当您按 Ctrl + C 时看到Read EOF的原因;如果之后检查ferror(stdin),您会看到它返回非零值(表示发生了错误)。在这种情况下,“错误”是EINTR,“被信号打断”。

另请注意,当您按某些键(如光标或功能键)时,您会看到生成多个字符,通常以27和91开头(十进制; 0x1B 0x5B,十六进制; "\033["如果表示为C字符串文字)。这些通常是但不总是ANSI转义序列。通常,它们是特定于终端的代码,可以使用terminfo数据库通过tigetstr()tigetnum()tigetflag()获取。

更容易实现的方法是使用Curses库;大多数系统上的ncurses或Windows计算机上的PDCurses。它们不仅提供了更简单的界面,而且还以特定于终端的方式实现,以实现跨系统的最大兼容性。

使用Curses函数的C程序可以针对任何Curses库进行编译,因此可以在Linux,Mac和Windows机器上编译和运行相同的C源文件。但是,ncurses确实包含很多扩展,其他Curses库可能不会提供这些扩展,例如PDCurses。