非缓冲stdin读取

我的testing应用程序是

#include <sys/types.h> #include <sys/wait.h> #include <signal.h> #include <unistd.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <fcntl.h> int main(int argc, char *argv[], char *envp[]) { int fd[2]; if(pipe(fd) < 0) { printf("Can\'t create pipe\n"); exit(-1); } pid_t fpid = fork(); if (fpid == 0) { close(0); close(fd[1]); char *s = (char *) malloc(sizeof(char)); while(1) if (read(fd[0], s, 1)) printf("%i\n", *s); } close(fd[0]); char *c = (char *) malloc(sizeof(char)); while (1) { if (read(0, c, 1) > 0) write(fd[1], c, 1); } return 0; } 

我想在每个input的字符后面看到char-code。 但实际上* s仅在控制台中的“\ n”后面打印。 所以看起来像标准input(desc 0文件)被缓冲。 但是读取function是无缓冲的,不是吗? 我在哪里错了。

UPD:我使用Linux。

所以解决scheme是

 #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <termios.h> int main(int argc, char *argv[], char *envp[]) { int fd[2]; if(pipe(fd) < 0) { printf("Can\'t create pipe\n"); exit(-1); } struct termios term, term_orig; if(tcgetattr(0, &term_orig)) { printf("tcgetattr failed\n"); exit(-1); } term = term_orig; term.c_lflag &= ~ICANON; term.c_lflag |= ECHO; term.c_cc[VMIN] = 0; term.c_cc[VTIME] = 0; if (tcsetattr(0, TCSANOW, &term)) { printf("tcsetattr failed\n"); exit(-1); } pid_t fpid = fork(); if (fpid == 0) { close(0); close(fd[1]); char *s = (char *) malloc(sizeof(char)); while(1) if (read(fd[0], s, 1)) printf("%i\n", *s); } close(fd[0]); char *c = (char *) malloc(sizeof(char)); while (1) { if (read(0, c, 1) > 0) write(fd[1], c, 1); } return 0; } 

不幸的是,你正在寻找的行为在标准的ANSI C中是不可能的,UNIX终端I / O的默认模式是面向行的,这意味着你总是需要一个输入的\n字符来检索输入。 您需要使用终端I / O设施,以便您以非规范模式编程,以便每个按键都能触发一个事件。 在Linux / UNIX上,您可以查看<termios.h>标题或ncurses库。

在我看来,你的解决方案有点复杂。 仍然不明白为什么你需要管道和2过程。

 #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <termios.h> int main(int argc, char *argv[], char *envp[]) { struct termios term, term_orig; if(tcgetattr(0, &term_orig)) { printf("tcgetattr failed\n"); exit(-1); } term = term_orig; term.c_lflag &= ~ICANON; term.c_lflag |= ECHO; term.c_cc[VMIN] = 0; term.c_cc[VTIME] = 0; if (tcsetattr(0, TCSANOW, &term)) { printf("tcsetattr failed\n"); exit(-1); } char ch; while (1) { if (read(0, &ch, 1) > 0) printf(" %d\n", ch); } return 0; } 

Unix在内核中缓存你的tty字符,以便程序不必单独处理行编辑,除非他们想要。

您可以指示tty驱动程序立即为您提供字节。 有各种各样的库使这比使用原始的ioctl更容易一些。 你可以从termios(3)