我可以不用键盘访问stdin吗?

我用gcc编译了下面的代码

int main() { int a = 0; fprintf( stdin, "%d", 123 ); fscanf( stdin, "%d", &a ); printf( "%d\n", a ); return 0; } 

在我的期望,程序应该直接执行(即程序不会暂停,等待用户input)。 但它仍然停止,等待我的投入。

我想知道什么时候我试图写一些东西,以及如何修改这个代码,它可以直接执行?

stdin仅用于输入, stdout用于输出。 (4566976的答案显示了当你尝试输出到stdin时会发生什么)例如,请参阅标准流上的glibc文档

(简而言之,写入stdin是毫无意义的)

如果你打印出fprintf(stdin的返回值,你可以看到函数调用失败。

在shell中,你可以将某些东西放入进程的stdin中。

 #include <stdio.h> int main(void) { int a = 0, ret; printf("%d\n", ret = fprintf( stdin, "%d", 123 )); if (ret < 0) perror("fprintf"); fscanf( stdin, "%d", &a ); printf( "%d\n", a ); return 0; } 

 $ echo 123 | ./a.out -1 fprintf: Bad file descriptor 123 $ 

你可以ungetc()几个字符,然后用fscanf()读取它们。

 #include <stdio.h> int main() { int value = 0; ungetc ( '\n', stdin);//reverse order. newline first here but last from fscanf ungetc ( '3', stdin); ungetc ( '2', stdin); ungetc ( '1', stdin); fscanf ( stdin, "%d", &value); printf ( "value is %d\n", value); return 0; } 

输出:值是123

除了fprintf(stdin, bug,你还忘了stdin不是键盘,最新的C11标准不知道键盘,在Linux图形桌面上,只有X11服务器正在从物理键盘读取数据。

实际上,在像Linux这样的POSIX系统上, stdin可以是管道(7) (在你的shell中使用管道非常普遍), fifo(7) , socket(7) ,纯文件(通过重定向 )甚至/dev/null ,当然还有一个终端

现在有趣的是,终端通常是虚拟仿真设备(本世纪以后,我没有看到任何真正的物理终端,在博物馆之外),阅读伪造 。 由于历史原因,细节非常神秘。 阅读tty揭秘页面。 另请参阅ANSI转义代码 wikipage& console_codes(4)和tty(4) (因此请考虑/dev/tty/dev/console

你可以使用isatty(STDIN_FILENO)检查(使用isatty(3) ) stdin是一个终端(实际上是伪造的isatty(STDIN_FILENO)

实际上,当你真的想使用终端,我强烈建议使用像ncurses或GNU readline的库(都使用termios(3) )

不要忘记,I / O通常是缓冲的 ,明智地使用fflush(3) 。

顺便说一句,你应该已经编译了所有警告和调试信息( gcc -Wall -Wextra -g ),然后使用gdb调试器。 strace(1)也是非常有用的。

也许你想要自己的程序(但是这很奇怪,而且往往是错误的,除非你非常关心所有的含义;但是在面向事件的程序中处理信号(7)是非常有用的技巧,特别是那些一些GUI )。 请注意,管道的缓冲区大小是有限的(所以避免死锁 ,可能通过使用poll(2)进行 事件循环 )并读取PIPE_BUF并写入 。 你可能试过:

 #include <stdio.h> #include <stdlib.h> #include <unistd.h> int main() { int pfd[2] = {-1,-1}; int a= 0; if (pipe(pfd)) { perror("pipe"); exit (EXIT_FAILURE); }; if (dup2(pfd[0],STDIN_FILENO)<0) { perror("dup2 stdin"); exit(EXIT_FAILURE);}; if (dup2(pfd[1],STDOUT_FILENO)<0) { perror("dup2 stdout"); exit(EXIT_FAILURE);}; if (printf("%d\n", 123)<=0) { perror("printf"); exit(EXIT_FAILURE); }; if (fflush(stdout)) { perror("fflush"); exit(EXIT_FAILURE); }; if (scanf("%d", &a)<1) { perror("scanf"); exit(EXIT_FAILURE); }; if (a != 123) { fprintf(stderr, "impossible happened a=%d\n", a); }; fprintf(stderr, "done...got a=%d\n", a); } 

您应该阅读高级Linux编程并学习更多关于系统调用(2) ; 它有几个相关的章节。 请仔细阅读pipe(2)和dup2(2) ,注意上面的程序对于更大的输出是错误的(大于PIPE_BUF ,在我的系统上是几千字节)

顺便说一句,你可以使用fmemopen(3)从内存缓冲区中获得可读的FILE* 。 为了写(比如用fprintf )到输出缓冲区,考虑open_memstream ,不要忘记在访问输出缓冲区之前将其open_memstream

你只是错误地认为fscanf(stdin, "format", ...); 不阻塞和等待输入,因为它。