首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

为什么write()在printf()之前执行?它不是应该是连续的吗?

在C语言中,write()和printf()是两个不同的函数,分别用于向文件描述符或标准输出流打印数据。它们的执行顺序取决于程序中的代码顺序和调用顺序。

write()函数用于向文件描述符写入数据,它是一个系统调用函数,直接与操作系统交互。它的执行是立即的,不会等待其他操作完成。当调用write()函数时,数据会被直接写入到文件描述符所指向的文件或设备中。

printf()函数用于向标准输出流打印数据,它是C语言库函数的一部分。printf()函数会将数据先存储在输出缓冲区中,然后在适当的时机将缓冲区的内容输出到终端。这个适当的时机可以是缓冲区满了、遇到换行符或程序结束等情况。

所以,如果在程序中先调用了write()函数,然后再调用printf()函数,write()函数会立即执行,将数据写入文件描述符指向的文件或设备中。而printf()函数会将数据存储在输出缓冲区中,直到适当的时机才会将缓冲区的内容输出到终端。

这种执行顺序的设计是为了提高程序的执行效率。由于write()函数是直接与操作系统交互的系统调用,执行速度较快。而printf()函数涉及到了输出缓冲区的管理和终端的IO操作,相对较慢。因此,如果write()函数的执行结果需要立即显示在终端上,可以先调用write()函数,再调用printf()函数。

需要注意的是,如果在调用write()函数后立即调用exit()函数或程序结束,printf()函数可能没有机会将输出缓冲区的内容输出到终端。为了确保输出缓冲区的内容被正确输出,可以在调用printf()函数后使用fflush(stdout)函数强制刷新输出缓冲区。

总结起来,write()函数和printf()函数的执行顺序是根据程序中的代码顺序和调用顺序决定的。write()函数是立即执行的系统调用函数,而printf()函数会将数据存储在输出缓冲区中,待适当时机再输出。这样的设计可以提高程序的执行效率。

页面内容是否对你有帮助?
有帮助
没帮助

相关·内容

互斥锁与读写锁:如何使用锁完成Go程同步?

println(a) // hi,ly } 源码见:go-easy/并发/锁/mutex1.go 输出是这样: hi,ly 该示例中,第14行Lock什么意思,代表main中开始锁住代码?...就像十字路口红绿灯一样,当灯变成红灯后,下一步如果想让再变成红灯,必须先把至少变回一次绿灯;而在此之前,要等待,我们正是利用这种等待特性,实现了Go程间同步行为。...第一行第一次Read data输出data有可能是1,也有很大概率是2。为什么输出不固定?当环境一致、输入条件一致时,电脑输出不应该固定?电脑不是最诚实?...在这里有个问题我们思考一下,第14行开启读线程内,不可以向内存写入数据? 并不是的。...所以我们看到,虽然“读”线程打印data并不是严格按照从小到大顺序打印,譬如第5行2.5比第6行2.3还要大,因为本质上它们是并发执行,结果是随机

1K10

Linux-基础IO

注意: 当前路径不是指可执行程序所处路径,而是指该程序运行为进程时所处路径。...,仔细看文件权限,与我们想要并不同,最后三项应该是 rw- 才对,这是因为存在叫做 权限掩码(umask) 东西,其通常默认为0002,与mode关系是 umask & mode,所以我们设置权限之前...并且为什么它们是连续??   其实0、1、2文件描述符已经被使用了!其分别是:标准输入、标准输出、标准错误!而它们是连续,其实也就是 数组下标!   ...我们经常说,Linux下一切皆文件,那么一个空文件,大小真的是0,其实在很久以前我们也探讨过,只要文件被创建,那么就不可能为0。...行刷新:\n之前内容进行刷新。 无刷新:无刷新。 ✈️FILE结构体   既然存在缓冲区这个东西,那么存储在哪呢?实际上 缓冲区是由FILE结构体来维护

10110
  • 干货——聊聊内存那些事(基于单片机系统)

    malloc分配内存空间逻辑上是连续,而在物理上可以不连续。...1024并不是做了完全强制限制。...碎片化测试时,p[2]、p[3]、p[4]大小应该是3*50=150,结果最大可以是160左右。 查看解释: 如果用malloc(n)来分配堆内存,那么分配内存比n大,为什么呢?...为什么Rom中还要有RW,因为掉电后RAM中所有的数据都丢失了,每次上电RAM中数据是被程序赋值,每次这些固定值就是存储ROM中为什么不包含ZI段呢,是因为ZI数据都是0,没必要包含,只要查询运行之前将...程序运行: 烧录到ROM中image文件与实际运行时ARM程序之间并不是完全一样。MCU执行过程是先将RW从ROM中搬到RAM中,因为RW是变量,变量不能存在ROM中。

    85110

    Linux fork那些隐藏开销

    不要觉得自己现在理解fork了就觉得一开始就是这么简单,说到底还是被灌输,回忆一下自己第一次接触fork时场景,懵圈?是不是想了好久也没想明白为什么一个函数可以返回两次?...和上述create_process比较,fork简直就是一个丑陋幽灵,不知道如此诡异东西怎么50年间被吹捧成了简单典范,若不是UNIX卫道士们鼓吹和灌输,fork应该是反面教材才对!...现在敲回车,执行fork后: 父进程写稀疏地址空间 子进程不执行exec 请观察fork之后,exec之前内存用量! 敲任意键执行exec!...我和UNIX fork神话 fork太过完美,没有任何参数,却承诺底层把一切帮你拿捏足够好,果真如此? 我第一次接触fork是2006年中软吉大工作试用期期间,我就是一个写Java。...但这貌似隐约间意味着,我心里,可能从一开始fork就不是一个解决问题正规方法,一直只是一个奇技淫巧。 然而,fork很多程序员心里成了一个神话。

    4.9K50

    编译原理学习笔记-基于less实践探究(一)

    我一年之前就看过一点,也就是单纯看过,现在可以说是基本毫无印象,一是没有做读书笔记,二是没有去实践,还是那句话纸上得来终觉浅,绝知此事要躬行。 为什么又想起来去重读龙书呢?...还是项目痛点,项目跑起来实在是太卡了,随着工程扩大,启动项目变成一个极其漫长事情!我在想为什么一定要用node作为前端工程基础呢?为什么不用其他语言呢?为什么不用golang去做呢?...突发奇想一个理想前端工程应该是怎么样?一个高效编译开发体验,一个简单文件目录就包含一个可执行文件加前端代码资源,一个容器化磨平差异不用担心windows,mac平台不同。...单位都不是一个单位,nodejs时间单位是ms而go是µs。 衍生一下,golang 并发一定比顺序执行?留下一个小疑问!..., 我们可以看到width字符之前或者 : 符合 前后都存在一定数量空格,这是需要删除 去除无效符号:在编译过程中例如";"这样符号,并没有什么实际意义可以删除(只是less场景下举例) 终止符号

    54920

    CC++练习题(三)

    ---- ---- 2、实现下面函数 写一个函数,原形是 int continumax(char outputstr,char intputstr) 功能: 字符串中找出连续最长数字串...所以 printf 返回其实不应该是输出字符个数,准确应该是向字符设备写入数据字节数。因为 char 占用一个字节,所以碰巧“printf 返回输出字符个数”,这个说法正确了。...---- ---- 4、#define中用到了array,但是array在后面才定义,合法为什么?最后程序输出什么?...注意一点 sizeof 是编译工具,计算结果是无符号。 ---- ---- 5、char p, a[16][8];问:p=a 是否会导致程序以后出现问题?为什么?...(printf 这个函数是一个 IO 函数 很多 IO 函数都是不可重入。也就是说如果在执行 printf 时候这个中断产生了,那么是不是 printf 又被调用了?

    2.2K40

    源码剖析signal和sigaction区别

    先来看这两个函数区别和实验: 一、实验 1、signal比sigaction简单,但signal注册信号sa_handler被调用之前把会把信号sa_handler指针恢复,而sigaction...2、signal调用sa_handler过程中不支持信号block;sigaction调用sa_handler之前会先将该信号block,sa_handler执行完成之后再恢复。...接着我用键盘ctrl+c连续发送5次SIGINT信号(图片第二个白色框所示^C),然后父进程也能接顺序处理。可以看出signal能block信号,并在调用完信号处理函数后接着处理之前block信号。...那与signal不支持信号block信号不是矛盾?...最后,至于应用程序中调用signal为什么到内核就变成了rt_sigaction了呢,也大概说一下吧: 反汇编一下实验一和实验二二进制程序(dis是我写一个反汇编程序指定函数shell命令,可以之前博客中找到

    2.3K11

    基于C语言指针一些思考

    为什么此刻会发生段错误呢?是不是颠覆了你此刻的人生观?...,由此我们可以推出一个结论: ❝一维数组名指向数组中第一个元素,数组名本质上是一个地址 ❞ image-20201028001056553 众所周知,数组底层是一块连续内存,p[0]也就是取p指向内存中存数...接下来看我们重头戏---二级指针和二维数组,上面的小例子说明,当声明一个二维数组时候,数组名并不是一个二级指针,我们印象中,一个2*2二维数组在内存中划分是这样: image-20201028003930875...,不是二级指针(指向指针指针),它还是简简单单指向了这块内存空间起始,假设声明了一个p[m][m]这样数组,p[i][j]指的是取p地址往后偏移n * i * m + n * j个字节地址数...不急,请看图,图中p是一个2*2二维数组: image-20201028005653611 至此,我们终于搞明白了第二章节程序会出现段错误,二维数组开辟内存还是一块连续内存,并不是我们所想象拥有几行几列内存

    39520

    keil调试程序断点设置技巧

    而当你设置为写(Write)访问时,你会发现从复位程序开始运行后,程序会停止某个地方,这是为什么?当你知道全局变量会在进入 main 函数之前被初始化时,你也就明白为什么了。...首先设置一个你需要断点: 打开断点窗口,并双击你之前设置断点: 设置 Command 为【printf(“USRAT_Init()\n”)】(注意\n,否则可能不能输出,这个应该是 KEIL...如果说你想让断点代码位置运行多次之后才输出一条信息也是可以,只要设置 Count 即可。 这里可能你会问,这 printf 不就是我们写打印函数?事实上,是,也不是。...=)程序执行暂停或执行命令之前比较变量值 。  当 Expression 解析为代码地址时,将执行执行中断(E)。到达指定代码地址时触发断点。代码地址必须引用 CPU 指令第一个字节。...每条 CPU 指令之后重新计算条件表达式,并且会大大减慢程序执行速度。 该计数值指定次数断点表达式必须计算为 TRUE 断点触发之前数目。

    3.1K11

    初识Linux · 重定向和缓冲区

    那么这个现象奇怪?其实并不算奇怪,因为我们知道文件描述符1虽然被关闭了,但是实际上只是没给stdout而已,给了新开文件log.txt,那么,这是不是一种重定向呢? 答案:是!...之后,我们确定了我们使用exit刷新缓冲区一定不是系统层面的,那么在那篇文章,我们知道了exit刷新是上层缓冲区,和我们上文所说缓冲区是否是同一个呢?...我们结合fprintf,fprintf参数为: 原本printf是将内容打印到1上,fprintf第一个参数改变了1,改成了对应文件对象,所以结合fprintf,dup2函数参数应该是dup2(...\n"; write(1,message,strlen(message)); fork(); return 0; } 注意那个fork,我们往1里面写入了三个字符串,但是为什么往一个文件里面...,printf和fprintf都打印了两行,但是write函数只打印了一个呢?

    12210

    基础IO理解与操作 - fd

    Linux下一切皆文件,也就是说冯诺依曼体系下任何东西,均可视为文件?为什么能这么说呢?         你还记得最初从电脑建立那个空白文件夹?我们从那里说起吧。...(来自百度百科)         这就是我们平时所能理解文件,一个文件通常包含属性和内容。 文件 = 内容 + 属性         那么这里属性也是这个文件数据?...但是,这里显示屏和键盘难道不是硬件?是的,也是文件。        ...重定向&追加重定向引入         那么我们这里能否改变一下呢,如果我们提前关闭了默认打开文件呢?比如关闭显示器stdout这个文件,执行printf会发生什么后果呢?...这是因为我们之前编译器默认打开了stdout即显示屏这个尾文件,内核里文件描述符fd指向,我们切断1和显示屏关系,使其指向null,然后打开文件。

    76920

    c语言进阶(1)

    文本代码->可执行文件->通过双击可以执行该程序 生成可执行程序并运行程序 双击link世界 双击是程序干什么?将程序数据加载到内存当中,让计算机运行。...任何程序在运行之前,都必须被加载到内存当中。 接着让我们思考两个问题:1.为什么程序运行之前都要被加载到内存当中?快 2.程序被加载到内存之前,程序在哪里?硬盘当中。 有关变量   什么是变量?...那么,是在任何地方都可以被使用?并不是。 register 计算机里具有存储能力硬件:CPU:寄存器,cache,内存,硬盘/ssd/flash。离CPU越近存储单元,效率越高,单价越贵。...那么在下面这个函数中,为什么show()函数未定义,程序还是能够运行成功呢?  printf是包含在库函数里,那我们是什么时候去找printf定义和实现呢?是程序最后一步实现可执行链接时候。...1.全局变量可以跨文件访问?可以。 2.函数可以跨文件访问?可以。 为什么呢?大型项目一定是多文件,多个文件之间一定要进行数据交互。如果不能跨文件,交互成本比较高。

    8210

    C语言如何计算结构体大小(结构体内存对齐)

    应该是两个char类型,一个int类型,2*1+4答案不应该是6? 上面两个结构体内容是一样,只有顺序不一样,为何计算结果不一样呢? 我们就带着以上疑问去探索!...二、结构体对齐规则 我们经过上面的分析,发现结构体成员不是按照顺序在内存中连续存放,而是有一定对齐规则,接下来我们就研究结构体内存规则。...五、为什么存在内存对齐?...TIP: 我们设计结构体时,可以人为节省空间——让占用空间小成员尽量集中在一起。  例如我们之前例子,尽管两个结构体存成员变量一样,但是顺序不一样,结构体内存大小也是不同。...六、修改默认对齐数 对,你没有听错,默认对齐数是可以修改滴,当我们把默认对齐数修改为1时,结构体成员变量就是连续存储

    10310

    由 Go 结构体指针引发值传递思考

    1] 返回是一个 S 类型值赋值给变量 s,而之所以能够 S 类型变量 s 上调用 *S 类型 Write ,是因为 Go 支持隐式引用转换,这个调用完整写法应该是: s := sVals...[1] (&s).Write() Go 隐式引用转换后可以简写成 s := sVals[1] s.Write() 那么为什么第二个 Write 调用无法编译通过呢?...map 值传递 Go 中,所有的函数参数和返回值都是通过值传递,这意味着它们都是原始数据副本,而不是引用或指针。...为什么要这样设计 为什么 map 要返回一个副本回来,而不是返回原始对象地址?这种设计选择是出于安全性和一致性考虑。...例如一开始持有了一个元素地址,之后 map 发生重哈希,地址都变了,再用之前获取地址做操作,肯定会出问题。 既然返回是一个副本,那么想要做出修改的话就需要注意了。

    22710

    Memory Consistency and Cache Coherence —— 内存一致性

    不可能出现r1 = 0, r2 = 0情况。但是此程序会出现,是因为load比store先访问内存,也就是r1 = yx = 1之前执行, r2 = x y = 1之前执行。...为什么会出现这种情况呢?...2.支持cpu简单推测, 具有强一致性模型系统中,cpu可以准备好提交之前,推测性地乱序执行load。支持SCMIPS R10000就是使用了这种特性提高了性能。...但是具有宽松内存一致性模型系统中,cpu可以乱序执行load,而无需将这些加载地址与传入一致性请求地址进行比较。对于宽松一致性模型,这些load不是推测性。...看一宽松一致性模型个例子 data1 data2初始化为0,flag不等于set,r2和r3会全部等于0

    1.5K10

    【自定义类型详解】完结篇——枚举与联合体(共用体)详解

    联合体成员共用一块空间。 那我们来看一下大小到底是多大? 为什么是4个字节呢? 联合体un只有两个成员,char c; int i;c 大小1个字节,i是最大成员4个字节。...那此时un四个字节空间里放应该是这样内容: 假设左边低地址,右边高地址 那我们去给un.c赋值,是不是就会改变1个字节内容(因为un.c是1个字节)。...2.3使用联合体解求机器字节序问题 那接下来我们就使用联合体来解决一道题: 之前一篇文章——深度剖析整形数据在内存中存储 中讲解过一道题: 大家如果忘了字节序相关知识可以去复习一下..."); else printf("大端"); return 0; } 解释一下: 首先我们知道 i, c肯定占用是同一块空间: u.i = 1;执行之后,联合体u4个字节里放应该是...是最大成员大小,5个字节? 是8个字节哎!为什么呢? 我们一起来算一下: 首先最大成员大小是几?

    22610

    合法修改只读数据

    但是可能大多数人并不清楚为什么会发生段错误,那么本篇文章就来说说:从只读数据被映射到进程虚拟地址空间到写访问发生段错误整个过程,力求让大家搞清楚这里面的底层内核原理,讲完整个过程之后我们来通过一个示例代码让修改只读数据变得合法...那么你是否知道,究竟段错误是如何产生?那么下面几节我们就来分析下段错误产生整个过程。 3. 要从exec说起 我们首先打开第11行宏,让发生写访问之前,程序睡眠,然后编译后台运行。...3个段:第一个为可读可执行、第二个为只读、第三个为可读可写;按照我们直觉:第一个应该是代码段、第二个应该是只读数据段、第三个数据段,但是实际上真的是这样?...中会解析可执行文件文件头,找到程序头表,然后解析程序头表每一个表项,对每一个可加载段进行映射,这里有两个段(上面通过readelf -l工具可以看到), 分配映射为只读可执行和可读可写不可执行,然后我们就可以通过...538 到 541 判断了是写导致异常,然后设置vm_flags = VM_WRITE__do_page_fault中就会通过vma->vm_flags 来判断vma是否有写权限,从而很早时候就拦截非法地址访问

    1.2K20
    领券