歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux編程 >> Linux編程

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 的下載地址:請點這裡

Copyright © Linux教程網 All Rights Reserved