struct _IO_FILE { int _flags; #define _IO_file_flags _flags char* _IO_read_ptr; /* Current read pointer */ char* _IO_read_end; /* End of get area. */ char* _IO_read_base; /* Start of putback+get area. */ char* _IO_write_base; /* Start of put area. */ char* _IO_write_ptr; /* Current put pointer. */ char* _IO_write_end; /* End of put area. */ char* _IO_buf_base; /* Start of reserve area. */ char* _IO_buf_end; /* End of reserve area. */ /* The following fields are used to support backing up and undo. */ char *_IO_save_base; /* Pointer to start of non-current get area. */ char *_IO_backup_base; /* Pointer to first valid character of backup area */ char *_IO_save_end; /* Pointer to end of non-current get area. */ struct _IO_marker *_markers; struct _IO_FILE *_chain; int _fileno; #if 0 int _blksize; #else int _flags2; #endif _IO_off_t _old_offset; /* This used to be _offset but it's too small. */ #define __HAVE_COLUMN /* temporary */ unsignedshort _cur_column; signedchar _vtable_offset; char _shortbuf[1]; /* char* _save_gptr; char* _save_egptr; */ _IO_lock_t *_lock; #ifdef _IO_USE_OLD_IO_FILE };
structobstack /* controlcurrentobjectincurrentchunk */ { long chunk_size; /* preferred size to allocate chunks in */ struct _obstack_chunk *chunk;/* address of current struct obstack_chunk */ char *object_base; /* address of object we are building */ char *next_free; /* where to add next char to current object */ char *chunk_limit; /* address of char after current chunk */ union { PTR_INT_TYPE tempint; void *tempptr; } temp; /* Temporary for some macros. */ int alignment_mask; /* Mask of alignment for each object. */
struct _obstack_chunk *(*chunkfun) (void *, long); void (*freefun) (void *, struct _obstack_chunk *); void *extra_arg; /* first arg for chunk alloc/dealloc funcs */ unsigned use_extra_arg : 1; /* chunk alloc/dealloc funcs take extra arg */ unsigned maybe_empty_object : 1; /* There is a possibility that the current unsigned alloc_failed : 1; /* No longer used, as we now call the failed handler on error, but retained for binary compatibility. */ };
staticvoid __printf_buffer_as_file_commit (struct __printf_buffer_as_file *file) { /* Check that the write pointers in the file stream are consistent with the next buffer. */ assert (file->stream._IO_write_ptr >= file->next->write_ptr); assert (file->stream._IO_write_ptr <= file->next->write_end); assert (file->stream._IO_write_base == file->next->write_base); assert (file->stream._IO_write_end == file->next->write_end);
staticvoid __printf_buffer_do_flush (struct __printf_buffer *buf) { switch (buf->mode) { case __printf_buffer_mode_failed: case __printf_buffer_mode_sprintf: return; case __printf_buffer_mode_snprintf: __printf_buffer_flush_snprintf ((struct __printf_buffer_snprintf *) buf); return; ...... case __printf_buffer_mode_fphex_to_wide: __printf_buffer_flush_fphex_to_wide ((struct __printf_buffer_fphex_to_wide *) buf); return; case __printf_buffer_mode_obstack: __printf_buffer_flush_obstack ((struct __printf_buffer_obstack *) buf); return; } __builtin_trap (); }
在这里我们关注进入__printf_buffer_flush_obstack函数的这一分支
__printf_buffer_flush_obstack函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14
void __printf_buffer_flush_obstack (struct __printf_buffer_obstack *buf) { /* About to switch buffers, so record the bytes written so far. */ buf->base.written += buf->base.write_ptr - buf->base.write_base;
if (buf->base.write_ptr == &buf->ch + 1) { /* Errors are reported via a callback mechanism (presumably for process termination). */ obstack_1grow (buf->obstack, buf->ch); [...] } }