I have compiled the following code with gcc
int main() {
int a = 0;
fprintf( stdin, "%d", 123 );
fscanf( stdin, "%d", &a );
printf( "%d\n", a );
return 0;
}
In my expectation, the program should executes straightly (i.e., the program never pause and wait for user input). But it still stop, and wait for my input.
I want to know what happen when I try to write something to stdin and how to modify this code and it can execute straightly?
stdin
is for input only, stdout
is for output. (4566976's answer shows you what happens when you try to output to stdin
) See for example the glibc documentation on standard streams
(in short, writing to stdin
makes no sense at all)
If you print out the return value of fprintf(stdin
you can see that the function call fails.
In the shell you can pipe something into the stdin
of the process.
#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
$
You can ungetc()
a few characters and then read them with 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;
}
output: value is 123
In addition of the fprintf(stdin,
bug you also forgot that stdin
is not the keyboard. The latest C11 standard does not know about the keyboard. On a Linux graphical desktop, only the X11 server is reading from the physical keyboard.
Practically speaking, on POSIX systems notably such as Linux, stdin
can be a pipe(7) (using pipelines in your shell is very common), a fifo(7), a socket(7), a plain file (thru redirection) or even /dev/null
, and of course also a terminal.
The funny thing these days is that terminals are very often virtual emulated devices (I did not see any real physical terminal in this century, outside of museums), read about pseudotty. The details are quite arcane for historical reasons. Read the tty demystified page. See also ANSI escape code wikipage & console_codes(4) and tty(4) (so consider /dev/tty
and perhaps /dev/console
)
You can check (with isatty(3)) that stdin is a terminal (actually a pseudotty) using isatty(STDIN_FILENO)
...
Practically speaking, when you really want to use the terminal, I strongly recommend using a library like ncurses or GNU readline (both are using termios(3))
Don't forget that I/O is generally buffered, and use fflush(3) wisely.
BTW, you should have compiled with all warnings & debug info (gcc -Wall -Wextra -g
) then use the gdb
debugger. And strace(1) would have been very useful too.
Maybe you wanted to pipe to your own program (but that is weird, and often wrong, unless you take great care about all the implications; it is however a very useful trick for handling signal(7) in event oriented programs, notably those with some GUI). Beware that pipes have a limited buffer size (so avoid deadlocks, probably by having your event loop with poll(2)) and read about PIPE_BUF
and write. You might have tried:
#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);
}
You should read Advanced Linux Programming and learn more about syscalls(2); it has several chapters related to this. Read carefully pipe(2) and dup2(2) and be aware that the above program would be wrong for a larger output (bigger that PIPE_BUF
, which on my system is several kilobytes)
BTW, you can get a readable FILE*
from a memory buffer using fmemopen(3). For writing (e.g. with fprintf
) to an output buffer, consider open_memstream
and don't forget to fflush
it before accessing the output buffer.
You're simply incorrect thinking that fscanf(stdin, "format", ...);
does not block and wait for input, because it does.