setbuf(stdin,NULL) can't work, why?

K

kernelxu

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!
 
K

Keith Thompson

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?

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.
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.

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.
 
W

Walter Roberson

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?

I already covered that in one of my previous replies to you,
but here it goes again with more emphasis:

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.)
 
K

kernelxu

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

thanks.
it means the stream is ubuffered since nothing left for the second
"getchar()".
Now that it's undefined, forget it.
Changing buffering doesn't
affect the fact that getchar() returns the characters you entered; it
only changes the way that input is buffered.

That's the key point.
run the first program, I enter
abc
then, c1 = a and c2 = b
but the input stream is unbuffered ( setbuf(stdin, NULL) has been
executed, I also tried
setvbuf(stdin, NULL, _IONBF, 0) instead, and I got the return value 0
,which tells the calling is successful), getchar() just access only one
character from the buffer of the input stream.I think there should not
be other characters except the first entered one.

#include <stdio.h>

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

flag = setvbuf(stdin, NULL, _IONBF, 0);/***************/

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

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

I thought the input progress is

_____________________
__________ _______________________ | ________________
| one
|keyboard |----->|keyboard physical buffer |----->| |input
stream buffer |---|----->getchar()
|__________| |______________________| |
|________________| |

| stdin |

|_____________________|

is it right?
Changing buffering doesn't
affect the fact that getchar() returns the characters you entered; it
only changes the way that input is buffered.

what do you mean by " the way that input is buffered"?

would you please enrich your words? I'm failed to understand it.

thank you very much.
 
K

kernelxu

__________ _______________________ | ________________
| one
|keyboard |----->|keyboard physical buffer |----->| |input
stream buffer |---|----->getchar()
|__________| |______________________| |
|________________| |
| stdin |

|_____________________|

I'am sorry it's mass.
it is

stdin one character
keyboard------>keyboard physical buffer------->input stream
buffer---------------------->getchar()
 
K

kernelxu

stdin one character
keyboard------>keyboard physical buffer------->input stream
buffer---------------------->g­etchar()
oh god!
it should be
keyboard------>keyboard physical buffer------->input stream
buffer(stdin)------one character---------------->g­etchar()
 
K

kernelxu

Walter,thank you very much.
that's what I want.
would you please give me some advice about this topic.
what are the relevant books I should read ?
and, some web link would be better .

best regards to you.
 
R

Richard Tobin

I think there should not
be other characters except the first entered one.

"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".

-- Richard
 
V

Villy Kruse

"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".

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.

Villy
 
W

Walter Roberson

Walter,thank you very much.
that's what I want.
would you please give me some advice about this topic.
what are the relevant books I should read ?
and, some web link would be better .

Sorry, please clarify which "that" is that you want. I had written,


and it isn't clear whether you are asking about interaction with
modems and serial ports, or whether you are asking about full-
keyboard interaction in a graphical environment (e.g., where you
might want to be able to detect that the user has pressed -just- the
shift key, or distinguish the left control-key from the right control-key).
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,768
Messages
2,569,574
Members
45,051
Latest member
CarleyMcCr

Latest Threads

Top