priintf为什么能写到屏幕上文字呢?

    技术2022-05-19  24

    用了这么多年的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);来给屏幕文件加锁和解锁

       这是为了如果多线程中同时有几个线程要输出到屏幕,可能会乱了。

     


    最新回复(0)