用了这么多年的printf(),都不知道priintf到底做了什么,悲哀啊!
刚刚看看看VC的源码,原来printf使用_write写了字符串到文件句柄为1的文件中,这个句柄就是屏幕的句柄
printf函数:
int __cdecl printf (
const char *format,
...
)
{
... // 这里是一些处理不定参数的操作,就是把第一个参数的指针依次加一,就得到第二个、第三个、...参数,就不介绍了,
_ftbuf(buffing, stdout);
...
}
而stdout的定义是:
#define stdout (&__iob_func()[1])
函数__iob_func()又在是_file.c中实现的:
/*
* FILE descriptors; preset for stdin/out/err (note that the __tmpnum field
* is not initialized)
*/
FILE _iob[_IOB_ENTRIES] = {
/* _ptr, _cnt, _base, _flag, _file, _charbuf, _bufsiz */
/* stdin (_iob[0]) */
{ _bufin, 0, _bufin, _IOREAD | _IOYOURBUF, 0, 0, _INTERNAL_BUFSIZ },
/* stdout (_iob[1]) */
{ NULL, 0, NULL, _IOWRT, 1, 0, 0 },
/* stderr (_iob[3]) */
{ NULL, 0, NULL, _IOWRT, 2, 0, 0 },
};
/* These functions are for enabling STATIC_CPPLIB functionality */
_CRTIMP FILE * __cdecl __iob_func(void)
{
return _iob;
}
这里首先定义了一个有文件结构的数组的数组
__cdecl __iob_func返回了第一个,在#define stdout (&__iob_func()[1]) 有加了1,再取地址 就是返回了第二个文件的指针
这里没有定义文件名FILE结构(第8个指针是文件名)有文件名,因为不用文件名,输出到屏幕了还要什么文件名啊
接下来看看函数_ftbuf:
/***
*int _flush(stream) - flush the buffer on a single stream
*
*Purpose:
* If file open for writing and buffered, flush the buffer. If
* problems flushing the buffer, set the stream flag to error.
* Multi-thread version assumes stream lock is held by caller.
*
*Entry:
* FILE* stream - stream to flush
*
*Exit:
* Returns 0 if flushed successfully, or if no buffer to flush.,
* Returns EOF and sets file error flag if fails.
* File struct entries affected: _ptr, _cnt, _flag.
*
*Exceptions:
*
*******************************************************************************/
int __cdecl _flush (
FILE *str
)
{
REG1 FILE *stream;
REG2 int rc = 0; /* assume good return */
REG3 int nchar;
/* Init pointer to stream */
stream = str;
if ((stream->_flag & (_IOREAD | _IOWRT)) == _IOWRT && bigbuf(stream)
&& (nchar = (int)(stream->_ptr - stream->_base)) > 0)
{
if ( _write(_fileno(stream), stream->_base, nchar) == nchar ) { // 这里写入了字符串
/* if this is a read/write file, clear _IOWRT so that
* next operation can be a read
*/
if ( _IORW & stream->_flag )
stream->_flag &= ~_IOWRT;
}
else {
stream->_flag |= _IOERR;
rc = EOF;
}
}
stream->_ptr = stream->_base;
stream->_cnt = 0;
return(rc);
}
大家一定注意到了函数_fileno,再看看_fileno:
int __cdecl _fileno (
FILE *stream
)
{
_VALIDATE_RETURN((stream != NULL), EINVAL, -1);
return( stream->_file );
}
从_iob的定义中可以看出就是返回了一个1
那么,看了上面的分析我们就可以使用如下方式写到屏幕上字符了
char mc[] = "This is MyString/n";
_write(1,mc,strlen(mc));
快去试试吧!
提醒:
1.屏幕输出的文件句柄为1,不知道能不能跨平台,我没有看过其他的系统系的屏幕输出怎么写的
2.prinf中使用了_lock_str2(1, stdout);和_unlock_str2(1, stdout);来给屏幕文件加锁和解锁
这是为了如果多线程中同时有几个线程要输出到屏幕,可能会乱了。