没有键盘我可以访问stdin吗?

时间:2015-09-13 07:35:59

标签: c linux keyboard stdin

我用gcc编译了以下代码

int main() {

  int a = 0;

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

  return 0;
}

在我的期望中,程序应该直接执行(即,程序永远不会暂停并等待用户输入)。但它仍然停止,等待我的意见。

我想知道当我尝试向stdin写一些东西时会发生什么,以及如何修改这段代码并且它可以直接执行?

5 个答案:

答案 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 codeconsole_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)的人。请注意管道的缓冲区大小有限(因此请避免使用GUIdeadlocks {{}}},并阅读PIPE_BUFevent 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 Programmingsyscalls(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", ...);没有阻止并等待输入,因为它确实存在。