博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
glibc-printf
阅读量:2442 次
发布时间:2019-05-10

本文共 7754 字,大约阅读时间需要 25 分钟。

printf()函数定义在stdio-common/printf.c

#include 
#include
#include
#undef printf/* Write formatted output to stdout from the format string FORMAT. *//* VARARGS1 */int__printf (const char *format, ...){ va_list arg; int done; va_start (arg, format); done = vfprintf (stdout, format, arg); va_end (arg); return done;}#undef _IO_printfldbl_strong_alias (__printf, printf);/* This is for libg++. */ldbl_strong_alias (__printf, _IO_printf);
#define ldbl_strong_alias(name, aliasname) strong_alias (name, aliasname)
strong_alias,即取别名。网上有人提及这个strong alias好像是为了防止c库符号被其他库符号覆盖掉而使用的,如果__printf被覆盖了,还有printf和_IO_printf可以用。
vfprintf()声明在libio/stdio.h
/* Write formatted output to S from argument list ARG.   This function is a possible cancellation point and therefore not   marked with __THROW.  */extern int vfprintf (FILE *__restrict __s, __const char *__restrict __format,		     _G_va_list __arg);

typedef struct _IO_FILE FILE;

printf函数是通过vfprintf将format输出到stdout文件中,stdout是(FILE *)类型。stdout的定义也在libio/stdio.h中。

/* Standard streams.  */extern struct _IO_FILE *stdin;		/* Standard input stream.  */extern struct _IO_FILE *stdout;		/* Standard output stream.  */extern struct _IO_FILE *stderr;		/* Standard error output stream.  *//* C89/C99 say they're macros.  Make them happy.  */#define stdin stdin#define stdout stdout#define stderr stderr
libio/stdio.c
#undef stdin#undef stdout#undef stderr_IO_FILE *stdin = (FILE *) &_IO_2_1_stdin_;_IO_FILE *stdout = (FILE *) &_IO_2_1_stdout_;_IO_FILE *stderr = (FILE *) &_IO_2_1_stderr_;
_IO_FILE结构定义在libio/libio.h
struct _IO_FILE {  int _flags;		/* High-order word is _IO_MAGIC; rest is flags. */#define _IO_file_flags _flags  /* The following pointers correspond to the C++ streambuf protocol. */  /* Note:  Tk uses the _IO_read_ptr and _IO_read_end fields directly. */  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;//对应linux内核中文件描述符fd  #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 */  /* 1+column number of pbase(); 0 is unknown. */  unsigned short _cur_column;  signed char _vtable_offset;  char _shortbuf[1];  /*  char* _save_gptr;  char* _save_egptr; */  _IO_lock_t *_lock;#ifdef _IO_USE_OLD_IO_FILE};
_IO_2_1_stdin_、_IO_2_1_stdout_和_IO_2_1_stderr_的定义在libio/stdfiles.clibio/stdfiles.c
#ifdef _IO_MTSAFE_IO# if defined _LIBC || defined _GLIBCPP_USE_WCHAR_T#  define DEF_STDFILE(NAME, FD, CHAIN, FLAGS) \  static _IO_lock_t _IO_stdfile_##FD##_lock = _IO_lock_initializer; \  static struct _IO_wide_data _IO_wide_data_##FD \    = { ._wide_vtable = &_IO_wfile_jumps }; \  struct _IO_FILE_plus NAME \    = {FILEBUF_LITERAL(CHAIN, FLAGS, FD, &_IO_wide_data_##FD), \       &_IO_file_jumps};# else#  define DEF_STDFILE(NAME, FD, CHAIN, FLAGS) \  static _IO_lock_t _IO_stdfile_##FD##_lock = _IO_lock_initializer; \  struct _IO_FILE_plus NAME \    = {FILEBUF_LITERAL(CHAIN, FLAGS, FD, NULL), \       &_IO_file_jumps};# endif#else# if defined _LIBC || defined _GLIBCPP_USE_WCHAR_T#  define DEF_STDFILE(NAME, FD, CHAIN, FLAGS) \  static struct _IO_wide_data _IO_wide_data_##FD \    = { ._wide_vtable = &_IO_wfile_jumps }; \  struct _IO_FILE_plus NAME \    = {FILEBUF_LITERAL(CHAIN, FLAGS, FD, &_IO_wide_data_##FD), \       &_IO_file_jumps};# else#  define DEF_STDFILE(NAME, FD, CHAIN, FLAGS) \  struct _IO_FILE_plus NAME \    = {FILEBUF_LITERAL(CHAIN, FLAGS, FD, NULL), \       &_IO_file_jumps};# endif#endifDEF_STDFILE(_IO_2_1_stdin_, 0, 0, _IO_NO_WRITES);DEF_STDFILE(_IO_2_1_stdout_, 1, &_IO_2_1_stdin_, _IO_NO_READS);DEF_STDFILE(_IO_2_1_stderr_, 2, &_IO_2_1_stdout_, _IO_NO_READS+_IO_UNBUFFERED);struct _IO_FILE_plus *_IO_list_all = &_IO_2_1_stderr_;INTVARDEF(_IO_list_all)
_IO_2_1_stdout_的FD = 0、_IO_2_1_stdin_的FD = 1、_IO_2_1_stderr_的FD = 2。FILEBUF_LITERAL用于初始化_IO_FILE,定义在libio/libioP.h
#ifdef _IO_MTSAFE_IO/* check following! */# ifdef _IO_USE_OLD_IO_FILE#  define FILEBUF_LITERAL(CHAIN, FLAGS, FD, WDP) \       { _IO_MAGIC+_IO_LINKED+_IO_IS_FILEBUF+FLAGS, \	 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, (_IO_FILE *) CHAIN, FD, \	 0, _IO_pos_BAD, 0, 0, { 0 }, &_IO_stdfile_##FD##_lock }# else#  if defined _LIBC || defined _GLIBCPP_USE_WCHAR_T#   define FILEBUF_LITERAL(CHAIN, FLAGS, FD, WDP) \       { _IO_MAGIC+_IO_LINKED+_IO_IS_FILEBUF+FLAGS, \	 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, (_IO_FILE *) CHAIN, FD, \	 0, _IO_pos_BAD, 0, 0, { 0 }, &_IO_stdfile_##FD##_lock, _IO_pos_BAD,\	 NULL, WDP, 0 }#  else#   define FILEBUF_LITERAL(CHAIN, FLAGS, FD, WDP) \       { _IO_MAGIC+_IO_LINKED+_IO_IS_FILEBUF+FLAGS, \	 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, (_IO_FILE *) CHAIN, FD, \	 0, _IO_pos_BAD, 0, 0, { 0 }, &_IO_stdfile_##FD##_lock, _IO_pos_BAD,\	 0 }#  endif# endif#else# ifdef _IO_USE_OLD_IO_FILE#  define FILEBUF_LITERAL(CHAIN, FLAGS, FD, WDP) \       { _IO_MAGIC+_IO_LINKED+_IO_IS_FILEBUF+FLAGS, \	 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, (_IO_FILE *) CHAIN, FD, \	 0, _IO_pos_BAD }# else#  if defined _LIBC || defined _GLIBCPP_USE_WCHAR_T#   define FILEBUF_LITERAL(CHAIN, FLAGS, FD, WDP) \       { _IO_MAGIC+_IO_LINKED+_IO_IS_FILEBUF+FLAGS, \	 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, (_IO_FILE *) CHAIN, FD, \	 0, _IO_pos_BAD, 0, 0, { 0 }, 0, _IO_pos_BAD, \	 NULL, WDP, 0 }#  else#   define FILEBUF_LITERAL(CHAIN, FLAGS, FD, WDP) \       { _IO_MAGIC+_IO_LINKED+_IO_IS_FILEBUF+FLAGS, \	 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, (_IO_FILE *) CHAIN, FD, \	 0, _IO_pos_BAD, 0, 0, { 0 }, 0, _IO_pos_BAD, \	 0 }#  endif# endif#endif
其中,FD赋值给了_fileno。我们回到vfprintf的分析,vfprintf的具体实现本文就不详细讲解,主要原理是格式化字符串,最后将字符串输出到文件中,也就是stdout中。至于如何输出,则和_IO_file_jumps关系密切,_IO_file_jumps的定义在libio/fileops.c
const struct _IO_jump_t _IO_file_jumps ={  JUMP_INIT_DUMMY,  JUMP_INIT(finish, INTUSE(_IO_file_finish)),  JUMP_INIT(overflow, INTUSE(_IO_file_overflow)),  JUMP_INIT(underflow, INTUSE(_IO_file_underflow)),  JUMP_INIT(uflow, INTUSE(_IO_default_uflow)),  JUMP_INIT(pbackfail, INTUSE(_IO_default_pbackfail)),  JUMP_INIT(xsputn, INTUSE(_IO_file_xsputn)),  JUMP_INIT(xsgetn, INTUSE(_IO_file_xsgetn)),  JUMP_INIT(seekoff, _IO_new_file_seekoff),  JUMP_INIT(seekpos, _IO_default_seekpos),  JUMP_INIT(setbuf, _IO_new_file_setbuf),  JUMP_INIT(sync, _IO_new_file_sync),  JUMP_INIT(doallocate, INTUSE(_IO_file_doallocate)),  JUMP_INIT(read, INTUSE(_IO_file_read)),  JUMP_INIT(write, _IO_new_file_write),  JUMP_INIT(seek, INTUSE(_IO_file_seek)),  JUMP_INIT(close, INTUSE(_IO_file_close)),  JUMP_INIT(stat, INTUSE(_IO_file_stat)),  JUMP_INIT(showmanyc, _IO_default_showmanyc),  JUMP_INIT(imbue, _IO_default_imbue)};libc_hidden_data_def (_IO_file_jumps)
至于怎么跳转到这些函数,以及如何跳转到linux内核,由于涉及到glibc的一些细节,这里简单介绍一下进入内核后的情况:进入linux内核后,调用write(),在write之前所有的代码都是C库的代码,可以说是和平台无关的。而涉及到具体输出,就要调用操作系统提供给的接口。调用write()后,通过系统调用进入内核空间,首先是sys_write(),这个函数代码位于fs/read_write.c中。一进入sys_write(),就要根据传进来的fd描述符找到相应的file结构。对于标准输出,fd = 1,每个进程的进程控制块都有一个打开文件的数组files。file结构就是根据fd在这个数组中查找到相应的结构。找到结构后,就会调用file->write()来向外输出。具体输出到哪里,就要看file结构对应的设备驱动是什么。
通过本文可以理解:文件描述符0、1和2和stdout、stdin和stderr对应,如果要修改linux内核中文件描述符相关代码,一定要注意文件描述符0、1和2的分配和回收,否则会导致终端没有输出信息,也无法和内核输入信息。

转载地址:http://kdsqb.baihongyu.com/

你可能感兴趣的文章
如何在WhatsApp中引用某人
查看>>
1080驱动此图形驱动程序_如何更新图形驱动程序以获得最佳游戏性能
查看>>
xbox手柄映射_如何在Windows 10中重新映射Xbox One控制器的按钮
查看>>
assistant字体_如何查找和删除Google Assistant的存储语音数据
查看>>
如何从iPhone的音乐应用程序中删除Apple Music
查看>>
国内wifi用不了谷歌_如何使用Google Wifi阻止不适当的网站
查看>>
word 粘贴富文本_如何在Word 2013中复制和粘贴具有跟踪更改的文本
查看>>
linux gnome卡机_使用GNOME盒在Linux上轻松创建KVM虚拟机
查看>>
word定义标题样式级别_如何在Word 2013中添加和删除自定义标题标签
查看>>
前端时间轴的那根线_如何阻止人们在不取消友情的情况下在您的Facebook时间线上发布
查看>>
word域代码中添加空格_如何在Word 2013中自动添加两个空格
查看>>
word中有些字符不能显示_如何在Word中显示非打印字符
查看>>
如何在PlayStation 4或Pro上标记和共享屏幕截图
查看>>
如何在Android上设置多个用户个人资料
查看>>
如何在Eero Wi-Fi系统上转发端口
查看>>
word自动更正关闭_如何在OS X中关闭自动更正文本替换
查看>>
手机耳塞 录音同时外放_如何将Android手机切换为“单声道”(这样就可以戴一副耳塞)
查看>>
bug解决方法_巨大的macOS Bug允许没有密码的root登录。 解决方法
查看>>
笔记本后台静默录像_您如何在笔记本电脑上“静默”非HDD,非风扇相关的嗡嗡声?
查看>>
如何删除WhatsApp消息
查看>>