glibc中的printf如何输出到串口

Linux内核版本: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):

#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_printf
/* This is for libg++.  */
strong_alias (printf, _IO_printf);

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

extern int vfprintf (FILE *__restrict __s, __const char *__restrict __format,
 _G_va_list __arg);

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

/* 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

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

_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_2_1_stdout_之前,我们先看一下_IO_FILE(FILE和_IO_FILE是一回事,#define FILE _IO_FILE)的定义(glibc-2.3.6/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
};
struct _IO_FILE_plus
{
  _IO_FILE file;
  const struct _IO_jump_t *vtable;//IO函数跳转表
};

Glibc 的详细介绍请点这里
Glibc 的下载地址请点这里

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:http://www.heiqu.com/29bd7b48057dc471dae326d521f00283.html