由一段测试代码出发直观深入的理解标准I/O函数库对标准输入输出设置的缓冲区刷新策略

重要提醒: 标准I/O库会设置缓冲的, 但系统调用(如:write和read)是没有缓冲区的.

测试代码

//用标准I/O库中的函数getc,putc实现标准输入复制到标准输出
int main(void){
    int c;

    while((c = getc(stdin)) != EOF){    //任何时候只要要求一个从不带缓冲的流或带行缓冲的流中得到数据, 但数据已经被取空时, 即流链接的文件为空时, 进入等待, 那么就会冲洗所有输出流
        //将从标准输入链接的文件中读到的换行符忽略, 不写到输出缓冲区中
        if(c == '\n'){  
            //sleep(3);  //如果sleep打开, 就不会立刻重新回到while判断, 首先换行符不会输入到输出缓冲区中, 不会使得输出缓冲区刷新, 其次, sleep的这10秒不会要求从标准输入流中得到数据, 即不会触发冲洗所有输出流, 所以此时数据全在输出缓冲区中, 不会写道标准输出链接的文件中
            continue;   //如果slee不打开, 而是立刻执行continue, 那么就会重新回到while判断, 进而再次执行getc, 即要求了从带行缓冲的标准输入流得到数据, 但数据已经被取空, 即标准输入链接的文件为空, 就会引发冲洗所有输出流, 这也就是为什么换行符没有写入标准输出链接的文件中, 但标准输出仍然输出内容
        }
        //放入输出缓冲区, 由于输出缓冲区也是行缓冲, 所以当缓冲区中有换行符'\n'时, 才会将标准输出缓冲中的数据写到标准输出链接的文件中
        if(putc(c,stdout) == EOF){
            fprintf(stderr,"putc put c failed: %s.\n",strerror(errno));
            exit(1);
        }
        sleep(1);//每隔1秒才回到getc读取标准输入流链接的文件中的数据, 只要有标准输入的文件中还有数据, 就不会触发冲洗所有输出缓冲区, 所以不会出现每1秒标准输出出现一个字符
    }
    
    if(ferror(stdin)){  //真错
        fprintf(stderr,"getc failed: %s.\n",strerror(errno));
        exit(1);
    }
    else{               //没数据了
        fprintf(stdout,"EOF.\n");
        exit(0);
    }
}

测试结果及分析

  1. 标准输入的缓冲区刷新策略:
    标准输入的缓冲去区策略比较好理解. 运行程序后, 在输出设备上键入字符但并未键入回车前, 已经键入的字符会被保存在标准输入的缓冲区中, 并未写到标准输入链接的文件中; 当键入回车时, 由于标准输入的缓冲区是行缓冲, 所以会将缓冲区中的这一行数据刷新写入到标准输入链接的文件中, 标准输入的链接的文件中此时有了数据, getc开始工作, 每次取一个字节(一个字符), 直到取到文件末尾

  2. 标准输出的缓冲区刷新策略:
    跟标准输入一样, 标准输出也是行缓冲的文件流, 所以缓冲区如果有换行符’\n’就会引发刷新缓冲区, 将内容写入到标准输出;
    但是, 如果不将’\n’写入到标准输出的缓冲区中, 标准输出会不会刷新呢, 结果是标准输出也会刷新, 这是为什么呢, 根据apue书上的内容和合理的推测, 目前的结论是: 任何时候只要要求一个从不带缓冲的流或带行缓冲的流中得到数据, 但数据已经被取空时, 即流链接的文件为空时, 进入等待, 那么就会冲洗所有输出流. 按照这个结论, 试着解释一下为什么此时行缓冲区没有换行符但仍然被刷新了, 这是因为当标准输入被取空后, 再次执行getc时, 即要求了从带行缓冲的标准输入流得到数据, 但数据已经被取空, 即标准输入链接的文件为空, 就会引发冲洗所有输出流, 这也就是为什么换行符没有写入标准输出链接的文件中, 但标准输出仍然输出内容.

  • 5
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值