2015-09-13 204 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

相關問題