用了这么多年的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);来给屏幕文件加锁和解锁
这是为了如果多线程中同时有几个线程要输出到屏幕,可能会乱了。