Ошибка «Неподходящий ioctl для устройства» в C

У меня есть функция getch(), которую дал мне мой наставник, которая получает ввод с клавиатуры, не нажимая «ENTER». Но когда я запускаю его в Ubuntu 12 в Eclipse, я получаю следующую ошибку:

tcsetattr(): Inappropriate ioctl for device
tcsetattr ICANON: Inappropriate ioctl for device

Это мой код:

#include <stdio.h>
#include <unistd.h>
#include <termios.h>

char getch();

int main(int argc, const char* argv[])
{
    char c;
    do
    {
        c=getch();
        printf("%c",c);
    } while(c!='q');

    return 0;
}

char getch()
{
    char buf = 0;
    struct termios old = {0};
    if (tcgetattr(0, &old) < 0)
        perror("tcsetattr()");
    old.c_lflag &= ~ICANON;
    old.c_lflag &= ~ECHO;
    old.c_cc[VMIN] = 1;
    old.c_cc[VTIME] = 0;

    if (tcsetattr(0, TCSANOW, &old) < 0)
        perror("tcsetattr ICANON");
    if (read(0, &buf, 1) < 0)
        perror ("read()");
    old.c_lflag |= ICANON;
    old.c_lflag |= ECHO;
    if (tcsetattr(0, TCSADRAIN, &old) < 0)
        perror ("tcsetattr ~ICANON");
    return (buf);
}

ПРИМЕЧАНИЕ. Код РАБОТАЕТ в SSH Secure Shell. Но я должен получить эту работу в своей Ubuntu, так как я пишу свой код там. Спасибо


person Jjang    schedule 19.04.2013    source источник


Ответы (1)


Вероятно, это связано с тем, что Eclipse не предоставляет программам псевдотерминал. запускать под IDE. Попробуйте этот вариант, основанный на неблокирующем вводе-выводе, а не на элементах управления терминалом.

#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

#define perror_exit(msg) do { perror(msg); exit(1); } while(0)

#if defined EAGAIN && defined EWOULDBLOCK
#define retry_p(err) ((err) == EAGAIN || (err) == EWOULDBLOCK)
#elif defined EAGAIN
#define retry_p(err) ((err) == EAGAIN)
#elif defined EWOULDBLOCK
#define retry_p(err) ((err) == EWOULDBLOCK)
#else
#error "Don't know how to detect read-would-block condition."
#endif

int
main(void)
{
    int flags = fcntl(0, F_GETFL);
    if (flags == -1)
        perror_exit("fcntl(F_GETFL)");
    flags |= O_NONBLOCK;
    if (fcntl(0, F_SETFL, flags))
        perror_exit("fcntl(F_SETFL, O_NONBLOCK)");

    for (;;)
    {
       char ch;
       ssize_t n = read(0, &ch, 1);
       if (n == 1)
       {
           putchar(ch);
           if (ch == 'q')
               break;
       }
       else if (n < 0 && !retry_p(errno))
          perror_exit("read");
    }
    return 0;
}

Если это по-прежнему не работает, попробуйте изменить его так, чтобы он выполнял и то, и другое, что делает это, и что делает ваш getch(), игнорируя ошибки tcsetattr и tcgetattr при errno == ENOTTY.

Обратите внимание, что и этот, и исходный код заняты ожиданием ввода-вывода, что является плохой практикой. Что вам на самом деле следует делать, так это использовать библиотеку ncurses. , который имеет более сложный подход к одновременной обработке и ожиданию ввода, который лучше подходит для многозадачной среды, а также решает вашу проблему отсутствия терминала и множество других головных болей низкого уровня, которые вам не нужны. на что тратить силы.

person zwol    schedule 19.04.2013
comment
Между прочим, если у него нет псевдотерминала, базовое чтение из 0 будет блокироваться, поскольку это канал. - person Joshua; 19.04.2013
comment
Спасибо за попытку. Я также пытался запустить его из терминала. Не хватает ли Терминалу того же свойства, что и Eclipse? Или там должно работать? - person Jjang; 19.04.2013
comment
Исходная программа должна была работать в любом контексте, который называет себя терминалом. Я могу представить, что он не работает из-за тонкостей либо конкретной программы, реализующей Терминал, либо конкретной ОС, которую вы используете. Это именно та проблема, которую ncurses решит за вас. - person zwol; 19.04.2013