我用gcc编译了以下代码
int main() {
int a = 0;
fprintf( stdin, "%d", 123 );
fscanf( stdin, "%d", &a );
printf( "%d\n", a );
return 0;
}
在我的期望中,程序应该直接执行(即,程序永远不会暂停并等待用户输入)。但它仍然停止,等待我的意见。
我想知道当我尝试向stdin写一些东西时会发生什么,以及如何修改这段代码并且它可以直接执行?
答案 0 :(得分:3)
stdin
仅用于输入,stdout
用于输出。 (4566976的答案显示了当您尝试输出到stdin
时会发生什么)请参阅例如glibc documentation on standard streams
(简而言之,写stdin
毫无意义)
答案 1 :(得分:3)
如果打印出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
$
答案 2 :(得分:2)
除了fprintf(stdin,
bug之外,您还忘记了stdin
不是键盘。最新的C11标准不了解键盘。在Linux图形桌面上,只有X11服务器正在从物理键盘读取。
实际上,在POSIX系统(例如Linux)上,stdin
可以是pipe(7)(在shell中使用pipelines非常常见),{{3 },fifo(7),普通文件(通过socket(7))或甚至redirection,当然还有/dev/null
。
这些天有趣的事情是,终端通常是虚拟模拟设备(我在本世纪没有看到任何真实的物理终端,在博物馆之外),阅读terminal。由于历史原因,细节非常神秘。阅读pseudotty页面。另请参阅tty demystified wikipage&amp; ANSI escape code和console_codes(4)(因此请考虑/dev/tty
,也许/dev/console
)
你可以使用isatty(STDIN_FILENO)
检查(tty(4)) stdin 是一个终端(实际上是伪)...
实际上,当您真的想要使用终端时,我强烈建议您使用isatty(3)或ncurses等库(两者都使用GNU readline)
请勿忘记I / O通常为termios(3),并明智地使用buffered。
顺便说一句,你应该编译所有的警告&amp;调试信息(gcc -Wall -Wextra -g
)然后使用gdb
调试器。 fflush(3)也非常有用。
也许你想管道你自己的程序(但这很奇怪,而且经常是错误的,除非你非常关心所有的含义;但它是在事件导向程序中处理strace(1)的一个非常有用的技巧,特别是那些有signal(7)的人。请注意管道的缓冲区大小有限(因此请避免使用GUI,deadlocks {{}}},并阅读PIPE_BUF
和event loop。你可能试过了:
#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);
}
您应该阅读poll(2)并详细了解write;它有几章与此相关。仔细阅读Advanced Linux Programming和syscalls(2)并注意上述程序对于更大的输出(大于PIPE_BUF
,在我的系统上是几千字节)是错误的
顺便说一句,您可以使用pipe(2)从内存缓冲区中获取可读FILE*
。要将(例如fprintf
)写入输出缓冲区,请在访问输出缓冲区之前考虑open_memstream
并且不要忘记fflush
。
答案 3 :(得分:2)
您可以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
答案 4 :(得分:1)
您只是错误地认为fscanf(stdin, "format", ...);
没有阻止并等待输入,因为它确实存在。