您的位置:首页 > 其它

在vs2008下使用cygwin(23):stdin,stdout和stderr

2008-10-21 15:11 681 查看

快乐虾 http://blog.csdn.net/lights_joy/ lights@hb165.com

本文适用于
Cygwin-1.16
Vs2008

欢迎转载,但请保留作者信息



stdin,stdout和stderr是3个标准的输入输出流,在vc中定义了,同样在cygwin中也定义了,但是由于cygwin和vc所使用的FILE结构的不同,对它们做了重命名处理:
#define cyg_stdin (_REENT->_stdin)
#define cyg_stdout (_REENT->_stdout)
#define cyg_stderr (_REENT->_stderr)
在这里_REENT将指向一个全局变量,这个全局变量使用了TLS,因而是线程安全的。
CYG_API struct _reent * __getreent (void);
# define _REENT (__getreent())
在_reent这个结构体中,定义了stdin,stdout和stderr三个FILE指针:
/*
* struct _reent
*
* This structure contains *all* globals needed by the library.
* It's raison d'etre is to facilitate threads by making all library routines
* reentrant. IE: All state information is contained here.
*/

struct _reent
{
int _errno; /* local copy of errno */

/* CYG_FILE is a big struct and may change over time. To try to achieve binary
compatibility with future versions, put cyg_stdin,cyg_stdout,cyg_stderr here.
These are pointers into member __sf defined below. */
__FILE *_stdin, *_stdout, *_stderr;
……………………..

/* These are here last so that __FILE can grow without changing the offsets
of the above members (on the off chance that future binary compatibility
would be broken otherwise). */
struct _glue __sglue; /* root of glue chain */
__FILE __sf[3]; /* first three file descriptors */
};
当需要使用putc,printf之类的函数的时候,这些函数将检查这个结构体是否已经初始化,如果没有则进行一次初始化操作:
int
_DEFUN(cyg_putc, (c, fp),
int c _AND
register CYG_FILE *fp)
{
#if !defined(PREFER_SIZE_OVER_SPEED) && !defined(__OPTIMIZE_SIZE__)
int result;
CHECK_INIT (_REENT, fp);
_flockfile (fp);
result = __sputc_r (_REENT, c, fp);
_funlockfile (fp);
return result;
#else
return _putc_r (_REENT, c, fp);
#endif
}
初始化过程由CHECK_INIT这个宏来控制,它的定义如下:
#define CHECK_INIT(ptr, fp) /
do /
{ /
if ((ptr) && !(ptr)->__sdidinit) /
__sinit (ptr); /
} /
while (0)
也就是说,它将调用__sinit函数来实际完成初始化工作:
/*
* __sinit() is called whenever stdio's internal variables must be set up.
*/

_VOID
_DEFUN(__sinit, (s),
struct _reent *s)
{
__sinit_lock_acquire ();

if (s->__sdidinit)
{
__sinit_lock_release ();
return;
}

/* make sure we clean up on exit */
s->__cleanup = _cleanup_r; /* conservative */
s->__sdidinit = 1;

s->__sglue._next = NULL;
#ifndef _REENT_SMALL
s->__sglue._niobs = 3;
s->__sglue._iobs = &s->__sf[0];
#else
s->__sglue._niobs = 0;
s->__sglue._iobs = NULL;
s->_stdin = __sfp(s);
s->_stdout = __sfp(s);
s->_stderr = __sfp(s);
#endif

std (s->_stdin, __SRD, 0, s);

/* On platforms that have true file system I/O, we can verify
whether cyg_stdout is an interactive terminal or not, as part of
__smakebuf on first use of the stream. For all other platforms,
we will default to line buffered mode here. Technically, POSIX
requires both cyg_stdin and cyg_stdout to be line-buffered, but tradition
leaves cyg_stdin alone on systems without fcntl. */
#ifdef H***E_FCNTL
std (s->_stdout, __SWR, 1, s);
#else
std (s->_stdout, __SWR | __SLBF, 1, s);
#endif

/* POSIX requires cyg_stderr to be opened for reading and writing, even
when the underlying fd 2 is write-only. */
std (s->_stderr, __SRW | __SNBF, 2, s);

__sinit_lock_release ();
}
从这里可以看出_stdin,_stdout,_stderr这三个成员是由std函数来初始化的,这个函数定义如下:
static _VOID
_DEFUN(std, (ptr, flags, file, data),
CYG_FILE *ptr _AND
int flags _AND
int file _AND
struct _reent *data)
{
ptr->_p = 0;
ptr->_r = 0;
ptr->_w = 0;
ptr->_flags = flags;
ptr->_file = file;
ptr->_bf._base = 0;
ptr->_bf._size = 0;
ptr->_lbfsize = 0;
ptr->_cookie = ptr;
ptr->_read = __sread;
#ifndef __LARGE64_FILES
ptr->_write = __swrite;
#else /* __LARGE64_FILES */
ptr->_write = __swrite64;
ptr->_seek64 = __sseek64;
ptr->_flags |= __SL64;
#endif /* __LARGE64_FILES */
ptr->_seek = __sseek;
ptr->_close = __sclose;
#if !defined(__SINGLE_THREAD__) && !defined(_REENT_SMALL)
__lock_init_recursive (ptr->_lock);
/*
* #else
* lock is already initialized in __sfp
*/
#endif

#ifdef __SCLE
if (__stextmode (ptr->_file))
ptr->_flags |= __SCLE;
#endif
}
注意到调用时的第三个参数file,分别使用的是0,1和2。这三个值分别是windows对于标准输入,标准输出和标准错误的文件号。从这里可以看出,cygwin仅是使用一个FILE结构体对这三个windows提供的标准文件进行了封装,所有的操作最终将使用这三个文件号调用windows的系统服务完成。



参考资料

在vs2008下使用cygwin(1):前言(2008-10-16)
在vs2008下使用cygwin(2):i686-pc-cygwin/newlib/Makefile分析(2008-10-16)
在vs2008下使用cygwin(3):i686-pc-cygwin/newlib/libc/Makefile分析(2008-10-16)
在vs2008下使用cygwin(4):i686-pc-cygwin/newlib/libc/argz/Makefile分析(2008-10-16)
在vs2008下使用cygwin(5):i686-pc-cygwin/newlib/libc/stdlib/Makefile分析(2008-10-16)
在vs2008下使用cygwin(6):i686-pc-cygwin/newlib/libc/ctype/Makefile分析(2008-10-16)
在vs2008下使用cygwin(7):i686-pc-cygwin/newlib/libc/search/Makefile分析(2008-10-16)
在vs2008下使用cygwin(8):i686-pc-cygwin/newlib/libc/stdio/Makefile分析(2008-10-16)
在vs2008下使用cygwin(9):i686-pc-cygwin/newlib/libc/stdio64/Makefile分析(2008-10-16)
在vs2008下使用cygwin(10):i686-pc-cygwin/newlib/libc/string/Makefile分析 (2008-10-16)
在vs2008下使用cygwin(11):i686-pc-cygwin/newlib/libc/signal/Makefile分析 (2008-10-16)
在vs2008下使用cygwin(12):i686-pc-cygwin/newlib/libc/time/Makefile分析 (2008-10-16)
在vs2008下使用cygwin(13):i686-pc-cygwin/newlib/libc/locale/Makefile分析 (2008-10-16)
在vs2008下使用cygwin(14):i686-pc-cygwin/newlib/libc/reent/Makefile分析 (2008-10-16)
在vs2008下使用cygwin(15):i686-pc-cygwin/newlib/libc/misc/Makefile分析 (2008-10-16)
在vs2008下使用cygwin(16):i686-pc-cygwin/newlib/libc/machine/i386/Makefile分析 (2008-10-16)
在vs2008下使用cygwin(17):i686-pc-cygwin/newlib/libc/posix/Makefile分析 (2008-10-16)
在vs2008下使用cygwin(18):i686-pc-cygwin/newlib/libc/syscalls/Makefile分析 (2008-10-16)
在vs2008下使用cygwin(19):i686-pc-cygwin/newlib/libm/Makefile分析(2008-10-17)
在vs2008下使用cygwin(20):i686-pc-cygwin/newlib/libm/math/Makefile分析2008-10-17
在vs2008下使用cygwin(21):i686-pc-cygwin/newlib/libm/common/Makefile分析(2008-10-17)
在vs2008下使用cygwin(22):使用tls(2008-10-20)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: