Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
251 views
in Technique[技术] by (71.8m points)

c - How to get the character last time ungetc puts back into a FILE*

Suppose I have a FILE* created by fopencookie, what happens if I call ungetc on the FILE*? Suppose I've setvbuf on the FILE* as _IONBF to make it unbuffered. Looks like the fopencookie doesn't support a handler for ungetc.

The background is I want to run scanf on istream, see scanf on an istream object. One suggestion is to use fopencookie and I was trying to wrap istream as FILE* by fopencookie, the problem comes out is, I need to make sure the FILE* doesn't buffer anything, however, scanf will at least read one character ahead when parsing fields whose width is unknown, e.g. for %d it will continue to read until find space or end-of-line. I assume scanf will put the character back to the FILE* by ungetc, in which case I need to put this character back to the istream as well. Is it possible to know which character scanf ungets? Thanks.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

fopencookie is a GNU extension which, as far as I know, exists in no other C library.

The GNU libc implementation of stdio is decidedly hairier than it ought to be because of an ancient (pre-EGCS, if that means anything to you) attempt to make FILE objects directly usable as C++ streambuf objects - no foolin'! - but the answer to your question may be found here: https://sourceware.org/git/?p=glibc.git;a=blob;f=libio/genops.c#l722 (the implementation of ungetc being named _IO_sputbackc is one of the remaining vestiges of that ancient attempt) I'll quote the code, it's short:

722 int
723 _IO_sputbackc (fp, c)
724      _IO_FILE *fp;
725      int c;
726 {
727   int result;
728
729   if (fp->_IO_read_ptr > fp->_IO_read_base
730       && (unsigned char)fp->_IO_read_ptr[-1] == (unsigned char)c)
731     {
732       fp->_IO_read_ptr--;
733       result = (unsigned char) c;
734     }
735   else
736     result = _IO_PBACKFAIL (fp, c);
737
738   if (result != EOF)
739     fp->_flags &= ~_IO_EOF_SEEN;
740
741   return result;
742 }

What this is saying is that if the character pushed back is identical to the character right behind the read pointer in the FILE object's buffer, it just decrements the read pointer once; otherwise, _IO_PBACKFAIL is called. Digging around a bit more in that directory (in particular, in libioP.h and iofopncook.c) reveals that _IO_PBACKFAIL on a FILE created with fopencookie calls _IO_default_pbackfail That function is much longer and I'm not going to quote it, but what it does is allocate a special "backup buffer" and stash the character there. This backup buffer can grow to accomodate an arbitrary number of calls to ungetc if necessary.

So, the answer to your question is that no matter how many times you call ungetc in a row (or other library functions do it for you), your cookie functions will never get asked to do anything. It's all handled internal to the FILE. Per my answer to your other question, I strongly advise that you find some other approach, but for what you were trying to do, I don't see why you think you need to "put this character back to the istream as well."


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...