printf缓冲区踩坑

2023-05-16

问题

碰到了这样一段代码(经过简化的):

#include "stdio.h"
#include "unistd.h"
#include "sys/wait.h"

int main(){
    fork();
    printf("1\n");
    fork();
    printf("1\n");
    wait(NULL);
    return 0;
}

这里我们简单算一下, 结果会打印几个1嘞?

  • 进程数: 2, line: 6
  • 进程数: 2, line: 7 打印数: 2
  • 进程数: 4, line: 8
  • 进程数: 4, line: 9 打印数: 4
  • 共计打印6次

看一下结果gcc main.c && ./a.out , 确实是6个.

但是, 到这并没有完, 若将printf中的\n去掉, 将结果在一行显示, 就会看到一些不同的内容了:

image-20220514173406606

结果竟然有8个? 这这这, 多出来的两个是哪来的嘞?

揭秘

我们将printf的数字差异化, 可能就有眉目了.

int main(){
    fork();
    printf("1");
    fork();
    printf("2");
    wait(NULL);
    return 0;
}

image-20220514173602873

其中数字1, 在我们分析时应该是只打印2次, 但是却打印了4次. 二者的唯一差异就是\n.

经过查证, 发现是printf的缓冲区捣的鬼. 简单来说, printf在调用的时候, 为了提高效率, 并不会立刻将内容输出, 而是先放到缓冲区, 那么什么时候输出呢?

  • 标准输出时为line buffer. 既行缓冲, 当碰到\n时输出
  • 重定向时为full buffer. 当缓冲区满了输出, 一般为1kb

有没有发现什么是与我们这个问题相关的? line buffer啊, 这不就是是否添加\n的差别么.

现在应该可以回答, 为什么去掉\n时, 输出了8个数字了, 当时的状态如下:

image-20220514175544748

输出了8个的原因, 就是printf将内容写入到了缓冲区中, 而在fork的时候带着缓冲区一起复制了. 真相大白

扩展

刷新缓冲器

既然知道是缓冲区搞的鬼, 有没有办法在fork之前清掉缓冲区呢? 有的:

#include "stdio.h"
#include "unistd.h"
#include "sys/wait.h"

int main(){
    fork();
    printf("1");
  	// 刷新缓冲区
    fflush(stdout);
    fork();
    printf("2");
    fflush(stdout);
    wait(NULL);
    return 0;
}

这样做的时候, 再fork之前将缓冲区内容输出并清空, fork时缓冲区中没有数据, 就没问题啦.

修改缓冲区大小

既然前面发生问题是因为缓冲区, 那么能不能将缓冲区关掉呢? 在输出的时候不进行缓冲不就没问题了么? 确实可以

#include "stdio.h"
#include "unistd.h"
#include "sys/wait.h"

int main(){
    // 将标准输出的缓冲区关闭
    setbuf(stdout, NULL);
    fork();
    printf("1");
    fork();
    printf("2");
    wait(NULL);
    return 0;
}

full buffer

还记得在查资料的时候, 不光有line buffer, 还碰到了一个full buffer. 是在重定向的时候使用的.

之前说, 这段代码直接运行时没有问题的, 正常输出了6个. 是因为缓冲区使用了line buffer, 每次碰到换行都会刷新缓冲区.

#include "stdio.h"
#include "unistd.h"
#include "sys/wait.h"
int main(){
    fork();
    printf("1\n");
    fork();
    printf("2\n");
    wait(NULL);
    return 0;
}

那么, 如果说不刷新缓冲区, 也就是换成所谓的full buffer, 不是也会有问题么? 既然重定向结果时为full buffer, 那重定向一下试试咯:

./a.out > a.log

查看结构, 确实与预期相同.


原文链接: https://hujingnb.com/archives/780

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

printf缓冲区踩坑 的相关文章

  • vgg16网络裁剪并加载模型参数

    主要是测试下模型裁剪后转onnx的问题 删除vgg16网络全连接层 xff0c 加载预训练模型并重新保存模型参数 xff0c 将该参数用于转onnx模型格式 usr bin env python coding utf 8 64 Time 2
  • pth转onnx的三种情况

    usr bin env python coding utf 8 64 Time 2022 8 3 16 19 64 Author weiz 64 ProjectName cbir 64 File pth2onnx py 64 Descrip
  • 以vgg为backbone的简易图像检索系统

    图像检索 xff08 Content based Image Retrieval xff0c 简称CBIR xff09 即以图搜图 xff0c 基于图片语义信息 xff0c 诸如颜色 纹理 布局 CNN based高层语义等特征检索技术 该
  • img2pose: Face Alignment and Detection via 6DoF, Face Pose Estimation代码理解

    import argparse import os import sys import time import numpy as np from PIL import Image ImageOps from torchvision impo
  • 解决普通用户使用sudo找不到命令

    sudo bazel build c opt define MEDIAPIPE DISABLE GPU 61 1 mediapipe examples desktop face mesh face mesh cpu 出现 xff1a sud
  • sfm算法之三角化(三角测量)

    sfm算法流程一般是特征点提取 特征点匹配 计算本质矩阵 基础矩阵 xff0c 最后三角化 但是利用机械臂去观察周围 xff0c 前后帧姿态变化参数是具有的 xff0c 所以不需要通过基础矩阵获取 即利用机械臂的信息直接进行深度估计 已知
  • bazel构建项目案例(第三方库,编译成库,运行案例)

    使用bazel构建项目 xff0c 包含如何引入外部库 xff08 项目中引入了opencv和编译的tensorflow lite库 xff09 xff0c 如何编译成动态库和静态库 xff0c 以及如何调用编译好的库 项目根目录的所有文件
  • 各种小功能集二

    各种小功能集一 十一 C C 43 43 路径解析 头文件 std string UtilsGetPath const char pszFilename std string UtilsGetDirname const char pszFi
  • windows10配置paddleOCR的CPU版本总结

    paddleOCR的CPU版本依赖的库还是比较少的 如下 1 opencv库 本人配置的版本是opencv4 5 0 2 paddle inference 推理库 该库解压后有version txt文件 xff0c 版本信息如下 xff1a
  • 传统图像技术的边缘提取

    usr bin env python coding utf 8 import cv2 import os import numpy as np def laplacian img ksize 61 3 laplacian 61 cv2 La
  • TCP-UDP网络编程调试助手下载

    下载地址 xff1a 可能需要谷歌 xff1a 软件干净 xff0c 挺好用的 xff0c 如果有更好的 xff0c 欢迎留言 xff01 https www waveshare com wiki File TCP UDP Debug 7z
  • Data Matrix码的使用

    一 引言 Data Matrix原名Data code xff0c 由美国国际资料公司 International Data Matrix 简称ID Matrix 于1989年发明 Data Matrix又可分为ECC000 140与ECC
  • 小样本学习(Few-Shot Learning)训练参数意义

    一 常规参数 1 1 epoch 是指所有的训练数据都要跑一遍 假设有6400个样本 xff0c 在训练过程中 xff0c 这6400个样本都跑完了才算一个epoch 一般实验需要训练很多个epoch xff0c 直到LOSS稳定后才停止
  • 不同相机之间图片像素对应关系求解(单应性矩阵求解)

    一 场景 相机1和相机2相对位置不变 xff0c 相机拍摄图片有重叠 xff0c 求他们交叠部分的一一对应关系 数学语言描述为已知相机1图片中P点像素 u1 v1 xff0c 相机1中P点在相机2图片中像素值为 u2 v2 xff0c 它们
  • python协程学习

    一 什么是协程及实现方式 1 1 协程 又称微线程 xff0c 纤程 也称为用户级线程 xff0c 在不开辟线程的基础上完成多任务 xff0c 也就是在单线程的情况下完成多任务 xff0c 多个任务按照一定顺序交替执行 1 2 实现方式 g
  • 无法打开文件libboost_random-vc141-mt-s-x64-1_81.lib

    踩坑过程 xff1a 需要使用websocketpp工具 xff0c 得先安装boost 安装boost及websocketpp过程简单且顺利 xff0c 并且能正常能正常运行官方例程 把官方例程简单封装测试 xff0c 一切皆好 等把we
  • 如何一步让你图像分类达到90%以上精准度

    这段时间一直在做图像分类相关的项目 xff0c 也认识了很多这个领域的小伙伴们 xff0c 有不少小伙伴们都是刚接触图像分类 xff0c 对着各种个样的图像分类算法 xff1a AlexNet VGG 16 VGG 19 ResNet 都是
  • 常用9类图像数据增强处理方法(可应用于图像分类、目标检测等场景)-附Python源码

    本文将分享下我做图像识别项目工作过程中常用的关于图像分类数据处理方法 xff0c 如有不当之处 xff0c 欢迎大家指正 图像数据增强 我们做项目过程中 xff0c 经常会遇到某些类的图像数据出现严重不足 xff0c 比如低于100张 xf
  • 你可能不知道的室内无人机秘密都在这里(一)

    最近公司业务需求 xff0c 今年又要开始研究室内自主巡检无人机 xff0c 无人机作为现在机器人技术应用较为广泛的产品之一 xff0c 相信很多小伙伴们或多或少都知道了像大疆 易航这些牛逼的国货之光了 xff0c 不过除了这些 xff0c
  • 上万代码——室内自主巡检无人机项目攻城战(一)

    小伙伴们 xff0c 继前段时间爆肝多天做调研室内无人机综述和实现技术等干货后 xff0c 我终于打算开始项目攻城战了 xff0c 接下来的3个月 xff0c 我将把我们项目涉及到的一些关键技术 xff0c 一一为大家分享 xff0c 大家

随机推荐