【问题标题】:Writing chars to pipe in C在 C 中将字符写入管道
【发布时间】:2013-04-20 14:59:56
【问题描述】:

我有以下程序,它基本上是从键盘读取字符(getch() 无需单击“ENTER”即可执行此操作,函数取自此处:Capture characters from standard input without waiting for enter to be pressed) ,然后如果 char 是合法移动之一(左、右等),它会将其写入到 draw.out 正在读取的管道中。

draw.out 正在读取它收到的输入并打印到屏幕上。 (假设这个程序工作正常,我保证问题只出在下面的代码中)。

问题是:

  1. draw.out 的行为就像它一遍又一遍地接收我的输入一样。这意味着,出于某种原因,即使我只按了一次 DOWN 键,它也会发送 draw.out,就好像我点击了很多次一样。

  2. 发送一个输入后,我无法再发送,好像循环停止了一样。

为了这个问题我想了好几个小时……非常感谢帮助。

int main(int argc, const char* argv[])
{
pid_t child_pid;
int fda[2];
if(pipe(fda)<0)
    perror("pipe error");

if((child_pid=fork())<0)
    perror("fork error");
else
{
    //if we're in father
    if(child_pid>0)
    {
        char c=' ';

        //close read side
        close(fda[0]);

        while(c!=QUIT)
        {
            //get an instruction from keyboard
            while(c!=ROTATE && c!=LEFT && c!=RIGHT &&
                    c!=DOWN && c!=QUIT)
            {
                c=getch();
            }

            //write the instruction to pipe
            write(fda[1],&c,1);
            //notify the child
            kill(child_pid,SIGUSR2);

        }
    }
    //if we're in child process
    else
    {
        dup2(fda[0],0);
        close(fda[0]);
        close(fda[1]);
        execl("./draw.out","./draw.out",NULL);
    }
}

//close everything
close(fda[0]);
close(fda[1]);
return 0;
}

//this function works well in linux with tsch installed or in SSH bash shell
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);
}

【问题讨论】:

    标签: c char signals fork pipe


    【解决方案1】:

    发送字符c 后,您需要将其设置为ROTATELEFTRIGHTDOWN 以外的值。

    如果您不这样做,getch() 将永远不会被第二次调用...

    因此,在外部 while 的末尾(就在 kill 之后)或循环的开始(就在包含 getch() 调用的 while 之前)添加类似

    if (c != QUIT)
      c = ' ';
    

    【讨论】:

    • 天哪!非常感谢! 6个小时,头疼得厉害!我觉得很安心。谢谢
    【解决方案2】:

    将 while 循环更改为 do/while 循环以确保 getch() 始终至少被调用一次。

    do
    {
        c = getch();
    }
    while (c != ROTATE && c != LEFT && c != RIGHT && c != DOWN && c != QUIT);
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-02-12
      • 2012-01-28
      • 1970-01-01
      • 2020-02-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多