zoukankan      html  css  js  c++  java
  • C语言学习趣事_关于C语言中的输入输出流_续一

          这两天赶上高考,家里有参加高考的,所以没有来园子里面逛逛, 今天高考完了,得闲了,所以出来透透气。

          上次我写了些关于printf()函数的的文字, 感觉自己对输入输出不是很了解, 并且自己表述的也不是很完整,还几处小毛病,因此想接着上次的话题继续瞎掰。

          那么这次瞎掰点什么呢 ? 那就从输入输出说起吧..................

    1、流

        我不知道为什么国内要把stream 翻译成流, 不过这个翻译倒是挺形象的。 我们知道C语言是伴随那个伟大的系统——Unix——而成长的,在Unix及其衍生的系统中,

    系统资源都是当做文件来看待的。C继承了这个传统,当我们从键盘输入字符的时候,C会把输入设备(即键盘)当做文件来处理。当我们利用C开发工具提供的输入输出函数

    来进行输入和输出时,C会把输入输出的内容当做“流”来处理。

        实际上流是一个理想话的对象,实际输入或输出设备处理的内容映射到这个数据流中,而C会中这个数据流中获取自己需要的信息。

    2、文件

         文件: 不知道怎么精确定义这个名词, 如果照大部分资料来看,文件是指存储在存储介质上的一堆0101信息的集合,或者可以认为是存储介质上一块存储区域。

        前面说过在C中,系统资源当做文件来处理, 这里我们主要讨论设备文件。

        在C运行后,会默认自动打开三个设备文件: 标准输入文件、标准输出设备和标准错误输出文件。

        即:   STDIN   标准输入文件  (stdin)

                STDOUT  标准输出文件 (stdout)

                STDERR  标准错误输出文件 (stderr)

    在有些系统里面应该是这样定义的:  #define  STDIN_FILENO   0    

                                                   #define  STDOUT_FILENO  1

                                                   #define  STDERR_FILENO  2

    有的系统是这样定义的:

                                                  #define stdin     (&_iob[0])
                                                  #define stdout   (&_iob[1])
                                                  #define stderr    (&_iob[2])

    3、 缓冲型输入系统和非缓冲型输入系统

         缓冲型输入系统:是指当C要从从输入文件(这里值标准输入设备,通常就是键盘)读入数据流时,只有当用户按下Enter ——(char)13 后用户输入的内容才能被被C使用。

         非缓冲型的系统:是指当C从输入文件读如数据流时, 不需要等待用户按下Enter键,C就能立即使用。

         如下图所示:

    对于C而言,或者说对用C实现的执行实体而言,是否是缓冲或不缓冲,这个由系统决定,目前大部分系统对C而言是缓冲型输入系统。

    4、  getc()、putc()、getchar()、putchar()

    需要说明的是这两组函数应该是在效果上:  getc()== getchar()

                                                          putc()==putchar()

    但是他们的原型,或者说定义形式却是不一样的。

    首先来看:getc()和getchar()

    在C中getc()的函数原型:

    Exp:

         char  getc(FILE *);

         就是说如果要使用getch();函数你需要给他传递一个指针。

         那么getchar()是怎么实现的呢? 这里有两种实现方式: 函数和宏;  我们就说说宏的定义:

    Exp:

          #define   getchar()    getc(stdin)

    同样来看:putc()和putchar(); 同样putc()需要一个文件指针,即其函数原型如:

    Exp:

          int putc(FILE *);

    于是putchar()的宏定义就是:

    Exp:

        #define  putchar()  putc(stdout)

    5、 EOF

         在用getchar()时,我们会从标准输入设备一个一个字符的读取所输入的字符,包括空白字符,例如:空格 、制表符 和 回车;在进行判断的时候可以用一个EOF

    来判断是否是输入的结束,这样可以输入任何想输入的字符。

    Exp:

           char  chInPut;

           while(EOF != (chInPut=getchar() ))

             {

                   putchar(chInPut);

             }

    当我们输入:a  b  c  dd 

    就会有输出:a  b  c  dd

    6、getc()

         在VC 6.0中有两个get()的定义, 一个是宏,一个是函数

    宏的定义如下:

        #define getc(_stream)     (--(_stream)->_cnt >= 0  ? 0xff & *(_stream)->_ptr++ : _filbuf(_stream))   

    函数定义如下:

       _CRTIMP int __cdecl getc(FILE *);           

       在C语言的各家编译器提供厂商里面有一个不成为的“潜规则”,那就是如果一个标识符前面如果是以下划线开头,这样的标识符通常是编译器预定义的宏,或者预定义的标志符。   

       我们看宏定义;这里用到的宏实际还用到了一个预定义的函数:

                         _CRTIMP int __cdecl _filbuf(FILE *)

        从这个函数可以看出在getc()宏中使用的:_stream是一个具有文件指针类型性质的预定义标识符。为了弄明白这个宏我们需要知道FILE类型的各个域;

    其实FILE类型是另一个类型的重定义:  

    Exp :

    struct _iobuf

    {

            char *_ptr;    
            int   _cnt;     
            char *_base;
            int   _flag;
            int   _file;
            int   _charbuf;
            int   _bufsiz;
            char *_tmpfname;
    };

    typedef  _iobuf  FILE;

      从上面可知FILE类型的结构体具有一个_cnt的域;这样我们就来解析getc()的宏;首先看:

               --(_stream)->_cnt >= 0

       在C语言的规范里面,我们知道 -> 的预算优先级与后缀 --的一样,同时高于前缀 -- 的优先级, 因此这里就是每次执行这个宏的时候,就是先判断_stream->cnt - 1

    后其值是否大于等于0;如果大于或等于0的话,那么这个宏就返回:0xff & *(_stream)->_ptr++ ; 如果小于0的话,那么这个宏就返回: _filbuf(_stream)当大于等于

    0的时候就说明缓冲区内还有文本流字符,这时取出当前字符并与0xFF进行位与作为getc(_stream)的返回值, 并且将字符指针后移一位。

      当 _stream->cnt - 1的值小于0的时候就表示缓冲区内的字符已经全部遍历过。但这时缓冲区内的内容还存在,只是指向缓冲区的指针已经移动到缓冲区后面,因此这

    时就需要更新缓冲区内的内容,通过函数_filbuf(_stream)来实现, 函数_filbuf(FILE *) 同时将_stream的各个域重新赋值。

      细心的朋友也许可以发现: #define stdin     (&_iob[0])   中的_iob[0];其实也是一个FILE类型的指针数组,其引用是通过: extern FILE _iob[]; 来实现的。

    就像前面说的 va_list 一样_stream 标识符由编译器的提供商定义,并且由编译器解释。这里我们就不在讨论这个FILE类型的预定义标识符。

    如果那位大侠需要自己尝试做个C的编译工具,可以研究研究。

  • 相关阅读:
    懒懒的~~
    BigDecimal,注解
    遇到的一点问题些
    npm一点点
    TortoiseSvn问题研究(一)
    关于maven-基本
    HttpServletRequest二三事
    学习迭代1需求分析
    FMDB简单使用
    计算机中的事务、回滚
  • 原文地址:https://www.cnblogs.com/volcanol/p/2076907.html
Copyright © 2011-2022 走看看