微波EDA网,见证研发工程师的成长!
首页 > 硬件设计 > 嵌入式设计 > glibc中的printf如何输出到串口

glibc中的printf如何输出到串口

时间:11-22 来源:互联网 点击:
内核版本:2.6.14

glibc版本:2.3.6

CPU平台:arm

printf输出不一定是串口,也可以是LCD,甚至是文件等,这里仅以输出到串口为例。本文分析了printf和文件描述符0、1和2以及stdout、stdin和stderr的关系,通过这篇文章可以知道文件描述符0、1和2为什么对应着stdout、stdin和stderr,因为glibc就是这么定义的!!!

首先看glibc中printf函数的定义(glibc-2.3.6/stdio-common/printf.c):

[plain]view plaincopyprint?

  1. #undefprintf
  2. /*WriteformattedoutputtostdoutfromtheformatstringFORMAT.*/
  3. /*VARARGS1*/
  4. int
  5. printf(constchar*format,...)
  6. {
  7. va_listarg;
  8. intdone;
  9. va_start(arg,format);
  10. done=vfprintf(stdout,format,arg);//主要是这个函数
  11. va_end(arg);
  12. returndone;
  13. }
  14. #undef_IO_printf
  15. /*Thisisforlibg++.*/
  16. strong_alias(printf,_IO_printf);

strong_alias,即取别名。网上有人提及这个strong alias好像是为了防止c库符号被其他库符号覆盖掉而使用的,如果printf被覆盖了,还有_IO_printf可以用。跟踪vfprintf函数(),我们先给出该函数的声明,如下(glibc-2.3.6/libio/stdio.h):

[plain]view plaincopyprint?

  1. externintvfprintf(FILE*__restrict__s,__constchar*__restrict__format,
  2. _G_va_list__arg);

printf函数是通过vfprintf将format输出到stdout文件中,stdout是(FILE *)类型。stdout的定义如下(glibc-2.3.6/libio/stdio.h),顺被也给出stdin和stderr的定义:

[plain]view plaincopyprint?

  1. /*Standardstreams.*/
  2. externstruct_IO_FILE*stdin;/*Standardinputstream.*/
  3. externstruct_IO_FILE*stdout;/*Standardoutputstream.*/
  4. externstruct_IO_FILE*stderr;/*Standarderroroutputstream.*/
  5. /*C89/C99saytheyremacros.Makethemhappy.*/
  6. #definestdinstdin
  7. #definestdoutstdout
  8. #definestderrstderr

继续跟踪stdout(glibc-2.3.6/libio/stdio.c):

[plain]view plaincopyprint?

  1. _IO_FILE*stdin=(FILE*)&_IO_2_1_stdin_;
  2. _IO_FILE*stdout=(FILE*)&_IO_2_1_stdout_;
  3. _IO_FILE*stderr=(FILE*)&_IO_2_1_stderr_;

在继续分析_IO_2_1_stdout_之前,我们先看一下_IO_FILE(FILE和_IO_FILE是一回事,#define FILE _IO_FILE)的定义(glibc-2.3.6/libio/libio.h):

[plain]view plaincopyprint?

  1. struct_IO_FILE{
  2. int_flags;/*High-orderwordis_IO_MAGIC;restisflags.*/
  3. #define_IO_file_flags_flags
  4. /*ThefollowingpointerscorrespondtotheC++streambufprotocol.*/
  5. /*Note:Tkusesthe_IO_read_ptrand_IO_read_endfieldsdirectly.*/
  6. char*_IO_read_ptr;/*Currentreadpointer*/
  7. char*_IO_read_end;/*Endofgetarea.*/
  8. char*_IO_read_base;/*Startofputback+getarea.*/
  9. char*_IO_write_base;/*Startofputarea.*/
  10. char*_IO_write_ptr;/*Currentputpointer.*/
  11. char*_IO_write_end;/*Endofputarea.*/
  12. char*_IO_buf_base;/*Startofreservearea.*/
  13. char*_IO_buf_end;/*Endofreservearea.*/
  14. /*Thefollowingfieldsareusedtosupportbackingupandundo.*/
  15. char*_IO_save_base;/*Pointertostartofnon-currentgetarea.*/
  16. char*_IO_backup_base;/*Pointertofirstvalidcharacterofbackuparea*/
  17. char*_IO_save_end;/*Pointertoendofnon-currentgetarea.*/
  18. struct_IO_marker*_markers;
  19. struct_IO_FILE*_chain;
  20. int_fileno;//这个就是linux内核中文件描述符fd
  21. #if0
  22. int_blksize;
  23. #else
  24. int_flags2;
  25. #endif
  26. _IO_off_t_old_offset;/*Thisusedtobe_offsetbutitstoosmall.*/
  27. #define__HAVE_COLUMN/*temporary*/
  28. /*1+columnnumberofpbase();0isunknown.*/
  29. unsignedshort_cur_column;
  30. signedchar_vtable_offset;
  31. char_shortbuf[1];
  32. /*char*_save_gptr;char*_save_egptr;*/
  33. _IO_lock_t*_lock;
  34. #ifdef_IO_USE_OLD_IO_FILE
  35. };
  36. struct_IO_FILE_plus
  37. {
  38. _IO_FILEfile;
  39. conststruct_IO_jump_t*vtable;//IO函数跳转表
  40. };

下面我们看看_IO_2_1_stdout_的定义(glibc-2.3.6/libio/stdfiles.c),顺便给出_IO_2_1_stdin_和_IO_2_1_stderr_的定义:

[plain]view plaincopyprint?

  1. #defineDEF_STDFILE(NAME,FD,CHAIN,FLAGS)\
  2. struct_IO_FILE_plusNAME\
  3. ={FILEBUF_LITERAL(CHAIN,FLAGS,FD,NULL),\
  4. &_IO_file_jumps};
  5. DEF_STDFILE(_IO_2_1_stdin_,0,0,_IO_NO_WRITES);
  6. DEF_STDFILE(_IO_2_1_stdout_,1,&_IO_2_1_stdin_,_IO_NO_READS);
  7. DEF_STDFILE(_IO_2_1_stderr_,2,&_IO_2_1_stdout_,_IO_NO_READS+_IO_UNBUFFERED);

从这里我们可以看到,_IO_2_1_stdout_的FD = 0、_IO_2_1_stdin_的FD = 1、_IO_2_1_stder

Copyright © 2017-2020 微波EDA网 版权所有

网站地图

Top