2015-09-13 200 views
3

我编下面的代码用gcc我可以在没有键盘的情况下访问stdin吗?

int main() { 

    int a = 0; 

    fprintf(stdin, "%d", 123); 
    fscanf(stdin, "%d", &a); 
    printf("%d\n", a); 

    return 0; 
} 

在我的意料,程序应该笔直执行(即程序从未暂停并等待用户输入)。但它仍然停止,并等待我的输入。

我想知道当我尝试向标准输入写入某些内容时会发生什么,以及如何修改此代码,并且它可以直接执行?

+0

相关:http://stackoverflow.com/q/584868/694576 – alk

+1

你到底想达到什么目的?如果你想使用“123”而不是stdin的输入,你应该写一个函数,在这种情况下返回“123”,否则返回stdin的值。不要试图做到这一点。 –

回答

3

stdin仅用于输入,stdout用于输出。 (4566976的回答表明,当你尝试输出到stdin会发生什么)例如,见glibc documentation on standard streams

(总之,写stdin毫无意义可言)

1

你根本不正确思想,fscanf(stdin, "format", ...);做不阻止并等待输入,因为它确实。

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

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

实事求是地讲,在POSIX系统特别是如Linux,stdin可以是pipe(7)(使用pipelines在你的shell是很常见的),一个fifo(7),一个socket(7),一个纯文本文件(直通redirection),甚至/dev/null,和当然也是terminal

有趣的,这些天是终端很经常的虚拟仿真设备(我没有看到任何真实的物理终端在本世纪,博物馆以外),了解pseudotty。由于历史原因,细节非常神秘。阅读tty demystified页面。另请参见ANSI escape code WIKIPAGE & console_codes(4)tty(4)(所以考虑/dev/tty也许/dev/console

您可以检查(带isatty(3))是标准输入是使用isatty(STDIN_FILENO)终端(实际上是一个pseudotty)...

实际上讲,当你真的想要使用终端时,我强烈建议使用库如ncursesGNU readline(均使用termios(3)

不要忘记I/O通常是buffered,并明智地使用fflush(3)

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

也许你想管自己的程序(但是这很奇怪,而且往往是错误的,除非你非常关心所有的含义;然而这是一个在面向事件的程序中处理signal(7)非常有用的技巧,特别是那些与一些GUI)。请注意,管道的缓冲区大小有限(所以请避免使用deadlocks,可能是因为您的event loop使用了poll(2)),并阅读了大约PIPE_BUFwrite。你可能曾尝试:

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

你应该阅读Advanced Linux Programming和了解syscalls(2);它有几个相关的章节。请仔细阅读pipe(2)dup2(2)并意识到,上述方案将是错误的更大的输出(更大的是PIPE_BUF,这在我的系统是几千字节)

BTW,您可以使用fmemopen(3)内存缓冲区得到一个可读FILE* 。对于写入(例如使用fprintf)写入输出缓冲区,请考虑open_memstream,并且在访问输出缓冲区之前不要忘记写入fflush

+0

“非常感谢Basile !!我会试着研究你在答案中写的是什么,我当前的主题是二进制翻译,我相信它对我有帮助:)” – hwliu

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

+0

谢谢。这是一个棘手的方法,但它在我的实现中起作用。 – hwliu

相关问题