现在的位置: 首页 > 综合 > 正文

对于setbuf函数的解释

2013年10月06日 ⁄ 综合 ⁄ 共 5074字 ⁄ 字号 评论关闭

原文网址:http://bytes.com/topic/c/answers/222619-setbuf-stdin-null-cant-work-why

其中只摘取其中有价值的部分:

Question:

hi, everyone.
now, I'am confused on such a problem:

function setbuf(stdin, NULL) or setvbuf(stdin, NULL, _IONBF, 0)
can set the stadard input stream unbuffered.

however, why does my program work like buffered?

the program is below 

#include <stdio.h>

int main(void)
{
     char c1 = '\0';
     char c2 = '\0';

     setbuf(stdin, NULL);/***************/

     printf("\n begin \n");
     c1 = getchar();
     printf("c1 = %d\n", c1);
     c2 = getchar();
     printf("c2 = %d\n", c2);
     printf("\n over \n");

     /*system("pause");*/
     return 0;

} 

result
c2 = 10

If the input stream is unbuffered, where does the 'new line' character
come from?

but, if I change the program into the following one:

#include <stdio.h>

int main(void)
{
     char c1 = '\0';
     char c2 = '\0';

     printf("\n begin \n");
     c1 = getchar();
     printf("c1 = %d\n", c1);

     setbuf(stdin, NULL);/**********************/

     c2 = getchar();
     printf("c2 = %d\n", c2);
     printf("\n over \n");

     /*system("pause");*/
     return 0;

}

everything seems OK.

why did this happen?
I think setbuf() should be called before any operations on the
stream,and would be enough to be called only once in a source file.

can anybody give me some reasons?
best regards!

Answer1:

Presumably it comes from stdin.  If you enter a single character
followed by a newline, for example, c1 will hold the first character
you entered, and c2 will hold the newline.  Changing buffering doesn't
affect the fact that getchar() returns the characters you entered; it
only changes the way that input is buffered.

In what sense is it OK?  When I tried it, it effectively ignored the
newline character I entered; I don't call that OK.

> why did this happen?
> I think setbuf() should be called before any operations on the
> stream,and would be enough to be called only once in a source file.

Specifically:

    The setvbuf function may be used only after the stream pointed to
    by stream has been associated with an open file and before any
    other operation (other than an unsuccessful call to setvbuf) is
    performed on the stream.

(A call to setbuf() is equivalent to a call to setvbuf() with certain
argument values.)

Your second program is misbehaving because it invokes undefined
behavior.


Answer2:----终极解答

setbuf() has to do with the delivery of bytes between the
C library FILE* management layer and the OS I/O layer.

Calls to fread(), fgets(), fgetc(), and getchar() work within
whatever FILE* buffered data is available, and when that data
is exhausted, the calls request that the FILE* buffer be refilled
by the system I/O layer.

When full buffering is turned on, that refill operation results in the
FILE* layer requesting that the operating system hand it a full
buffer's worth of data; when buffering is turned off, that
refill operation results in the FILE* layer requesting that the
operating system return a single character.

Your error is in assuming that the operating system layer in
question is dealing with raw bytes directly from the terminal.
That is not the case. Instead, the relevant operating system layer
is dealing with bytes returned by the terminal device driver --
and the device driver does not pass those bytes up to the
operating system layer until the device driver is ready to do so.

As I indicated before, setting an input stream to be unbuffered
does NOT tell the operating system to tell the device driver
to go into any kind of "raw" single-character mode. There are
system-specific calls such as ioctl() and tcsetterm() that
control what the device driver will do.

In Unix-type systems, the terminal device driver by default works
on a line at a time, not passing the line onward until it detects
a sequence that indicates end-of-line. When the Unix-type
'line disciplines' are in effect, you can edit the line in various
ways before allowing it to be passed to the operating system.
For example, you might type cad and then realize you mistyped and so
press the deletion key and type an r; if you were to do so, and then
pretty return, it would be the word  car  that was passed to the
next layer, *not* the series of keys  cad<delete>r
The device driver buffers the input to allow you to edit it,
and setting your input stream to unbuffered in your program does NOT
affect that device driver buffering.

If you want to do single-character I/O and you will worry about
things like inline editting yourself in your program, then you
will need to use system-specific calls to enable that I/O mode.

Before you head down that path, you should keep in mind that
you cannot handle mouse-highlight and copy and paste operations
just by looking at the key presses themselves: you have to work
with the graphical layer to do that, and that can get very messy.
Because of that, character-by-character I/O is probably best
reserved for interaction with non-graphical devices such as
modems and serial ports. If you -really- want character-by-
character I/O, such as because you are programming a graphical
game, then it is probably best to find a pre-written library that
handles the dirty work for you.

Effectively, at this point in your programming career, you should
probably supress the memory that setbuf() can be applied to
input streams, and just work with line-by-line I/O. You -probably-
don't have much reason to apply setbuf() to output streams,
either (but you might want to get into the practice of
putting in fflush(stdout) calls after writing out information
that the user needs in order to decide on future inputs.)

Answer3:

"Unbuffered" doesn't mean "throw away characters instead of buffering
them".  It means "make characters available to getchar() etc as soon
the operating system returns them, rather than waiting until you've
got a buffer-full". 

Answer4:

The OS would in most cases buffer the data regardless what one would do
in a user level program, if not elsewhere then in the keyboard buffer.
The program can then fetch the data from the OS one character at a time
if stdin is unbufferd, or as many characters as is available if stdin
is buffered. 

太有价值了,有空翻译一下。

抱歉!评论已关闭.