Unbuffered stdin reading

My test application

#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; } 

I want to see the char code after each char entered. But actually * s is printed only after "\ n" in the console. It seems that stdin (file with desc 0) is buffered. But the read function has no buffering, right? Where am I mistaken.

UPD: I am using linux.

So the solution

 #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; } 
+7
c linux unix posix
source share
3 answers

Unfortunately, the behavior you are looking for is not possible with standard ANSI C, and the default mode for input / output of a UNIX terminal is line-oriented, which means you will always need the entered \n character to extract input. You will need terminal I / O facilities that allow you to program in non-canonical mode so that each keystroke triggers an event. On Linux / UNIX, you can view the header for <termios.h> or ncurses .

+12
source share

It seems to me that your decision is a little more complicated. Still don't understand why you need the pipe process and 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; } 
+3
source share

Unix buffers your tty characters partially inside the kernel, so programs do not need to individually process line editing if they don't want to.

You can instruct the tty driver to immediately provide you with bytes. There are various libraries that make this a little easier than using raw ioctl. You can start with termios(3) .

+2
source share

All Articles