【问题标题】:Why does the terminal freeze when running a C program?为什么在运行 C 程序时终端会死机?
【发布时间】:2020-10-16 16:59:42
【问题描述】:

我正在尝试以终端原始模式读取用户的输入表单。

这是启用原始模式并禁用一些转义字符和所有字符的函数。它还引用了 disableRawMode ,用于在读取输入后重新进入规范模式:

void enableRawMode() {
     if (tcgetattr(STDIN_FILENO, &orig_termios) == -1) 
        die("tcgetattr");
    atexit(disableRawMode);
    struct termios raw = orig_termios;
    raw.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON);
    raw.c_oflag &= ~(OPOST);
    raw.c_cflag |= (CS8);
    raw.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG);
    raw.c_cc[VMIN] = 0;
    raw.c_cc[VTIME] = 1;
    if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &raw) == -1)
        die("tcsetattr");
}

还有一些其他函数(editorReadKey & editorprocessKeypress)来读取按键并处理字符输入:

char editorReadKey() {
    int nread;
    char c;
    while ((nread = read(STDIN_FILENO, &c, 1) != 1)) {
        if (nread == -1 && errno != EAGAIN) 
            die("read");
    }
}

void editorProcessKeypress() {
    char c = editorReadKey();
    switch (c) {
    case CTRL_KEY('q'):
        exit(0);
        break;
    }
}

但是当我调用主程序中的函数时:

int main(void) {    
    enableRawMode();
    while (1) {
        editorRefreshScreen();
        editorProcessKeypress();
    }
    return 0;
}

我的终端刚刚死机,我必须重新启动它才能让它恢复工作。有什么理由说明为什么会发生这种情况?

【问题讨论】:

  • “编译时”和“运行时”是有区别的。
  • 如果您在main() 内的无限循环中插入输出,您多久会看到该输出?
  • 很抱歉。碰巧英语不是我的第一语言,我还在习惯它。编辑了问题。
  • @Yunnosch 我只使用无限循环,因为我想读取输入直到按下“q”。在这种情况下,我想循环将终止。
  • 你不会从editorReadKey() 返回任何东西,C 编译器只是接受它。这意味着您的任何密钥处理都不会触发,因此您的代码永远不会做任何事情,因此看起来很冻结。始终使用 -Wall 构建 C 代码

标签: c linux terminal


【解决方案1】:

也许这个例子能满足你的需要。输出很少,因为这是重点:)

terminal info saved
raw mode will be set now
Enter 'q' to exit!

terminal configuration restored

程序只是保存终端配置,进入原始模式并从输入中读取,直到读取“q”或用户按下 control-C。然后终端被重置并恢复配置。

#include <errno.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <termios.h>
#include <unistd.h>

typedef struct termios Termios;

void        editorProcessKeypress();
char        editorReadKey();
void        editorRefreshScreen();
void        enableRawMode(Termios*);
void        gameOver();
int         getMode(Termios*);
int         setMode(Termios*);

int main(void)
{ 
    Termios original_termios;
    Termios raw;
    if ( getMode(&original_termios) < 0)
    {
        fprintf(stderr,"Could not get terminal info");
        return(-1);
    }
    printf("terminal info saved\n");

    enableRawMode(&raw);

    printf("Enter 'q' to exit!\n");
    editorRefreshScreen();
    char in = editorReadKey();

    while( in != 'q' )
    {
           editorRefreshScreen();
           in = editorReadKey();
    };

    if ( setMode(&original_termios) < 0)
    {
        fprintf(stderr,"Could not reset terminal. Please run 'tput reset'!");
        return(-1);
    }
    printf("\nterminal configuration restored\n");
    return 0;
};

void enableRawMode(Termios* raw)
{
    raw->c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON);
    raw->c_oflag &= ~(OPOST);
    raw->c_cflag |= (CS8);
    raw->c_lflag &= ~(ECHO | ICANON | IEXTEN ) | ISIG;
    raw->c_cc[VINTR] = 3;
    raw->c_cc[VMIN] = 0;
    raw->c_cc[VTIME] = 10;

    signal(SIGINT, gameOver);

    printf("raw mode will be set now\n");
    if (tcsetattr(STDIN_FILENO, TCSAFLUSH, raw) < 0)
        printf("raw mode NOT set!!\n");
    fflush(stdin);
};

char editorReadKey() {
    int nread;
    char c = 0;
    while ((nread = read(STDIN_FILENO, &c, 1) != 1)) {
        if (nread == -1 && errno != EAGAIN) 
            return 0;
    };
    return c;
};


void        editorRefreshScreen()
{
    return;
};


void        gameOver()
{
    Termios reset;
    reset.c_iflag =  ~IGNCR | ICRNL | INPCK  | ISTRIP | IXON | BRKINT | ICANON;
    reset.c_oflag = ECHO | OPOST;
    reset.c_lflag = ECHO | ICANON | IEXTEN;
    tcsetattr(STDIN_FILENO, TCSANOW, &reset);
    printf("\n^C: Aborting... Issue a 'tput reset' if terminal not ok\n");
    exit(1);
};


int         getMode( Termios* term )
{
        return tcgetattr(STDIN_FILENO, term);
};


int         setMode(Termios* term)
{
        return tcsetattr(STDIN_FILENO, TCSANOW, term);
};

【讨论】:

    猜你喜欢
    • 2011-07-28
    • 1970-01-01
    • 1970-01-01
    • 2020-09-16
    • 1970-01-01
    • 1970-01-01
    • 2011-07-06
    • 1970-01-01
    • 2015-04-02
    相关资源
    最近更新 更多