我的测试应用程序是
#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;
}
我希望在每个输入的char后看到char代码。但实际上* s仅在控制台中的“\ n”之后打印。所以似乎stdin(带有desc 0的文件)被缓冲了。但是read函数是无缓冲的,不是吗?我哪里错了。
UPD:我使用的是linux。
所以解决方案是
#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;
}
答案 0 :(得分:12)
不幸的是,使用标准ANSI C无法实现您正在寻找的行为,并且UNIX终端I / O的默认模式是面向行的,这意味着您始终需要输入\n
个字符检索输入。您需要使用终端I / O工具,让您以 non-canonical 模式进行编程,以便每次按键触发一个事件。在Linux / UNIX上,您可以查看<termios.h>
标头或ncurses库。
答案 1 :(得分:4)
在我看来,你的解决方案有点复杂。仍然不明白为什么你需要管道和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;
}
答案 2 :(得分:2)
Unix在内核中缓冲你的tty字符部分,这样程序就不必单独处理行编辑,除非他们想要。
您可以指示tty驱动程序立即为您提供字节。有各种库使这比使用原始ioctl容易一些。您可以从termios(3)
开始。