C语言printf的一个刁钻Bug

2024年12月2日   |   by tgcode

C语言中的 printf() 有一个尴尬的问题,就是有时候不能立即输出,请看下面的代码:

#include
#include //sleep()所在的头文件
int main()
{
    printf("C语言中文网");
    sleep(5);  //程序暂停5秒钟
    printf("http://c.biancheng.netn");

    return 0;
}

这段代码使用了两个 printf() 语句,它们之间有一个 sleep() 函数,该函数的作用是让程序暂停 5 秒,然后再继续执行。

sleep() 是 Linux 和 macOS 下特有的函数,不能用于 Windows。当然,Windows 下也有功能相同的暂停函数,叫做 Sleep(),稍后我们会讲解。

注意开头的字母s,它们的大小写是不一样的。

在 Linux 或者 macOS 下运行该程序,会发现第一个 printf() 并没有立即输出,而是等待 5 秒以后,和第二个 printf() 一起输出了,请看下面的动图演示:

%title插图%num

我们不妨修改一下代码,在第一个 printf() 的最后添加一个换行符,如下所示:

printf(“C语言中文网n”);

再次编译并运行程序,发现第一个 printf() 首先输出(程序运行后立即输出),等待 5 秒以后,第二个 printf() 才输出,请看下面的动图演示:

%title插图%num

为什么一个换行符n就能让程序的表现有天壤之别呢?按照通常的逻辑,程序运行后第一个 printf() 应该立即输出,而不是等待 5 秒以后再和第二个 printf() 一起输出,也就是说,第二种情形才符合我们的惯性思维。然而,第一种情形该如何理解呢?

其实,这一切都是输出缓冲区(缓存)在作怪!

从本质上讲,printf() 执行结束以后数据并没有直接输出到显示器上,而是放入了缓冲区,直到遇见换行符n才将缓冲区中的数据输出到显示器上。更加深入的内容,我们将在本章的《进入缓冲区(缓存)的世界,破解一切与输入输出有关的疑难杂症》中详细讲解。

以上测试的是 Linux 和 macOS,我们不妨再测试一下 Windows,请看下面的代码:

#include
#include //Sleep()所在的头文件
int main()
{
    printf("C语言中文网");
    Sleep(5000);  //程序暂停5秒钟
    printf("http://c.biancheng.netn");

    return 0;
}

在 Windows 下,想让程序暂停可以使用 Windows.h 头文件中的 Sleep() 函数(S要大写),它和 Linux 下的 sleep() 功能相同。不过,sleep() 要求的时间单位是秒,而 Sleep() 要求的时间单位是毫秒,1 秒等于 1000 毫秒。这段代码中,我们要求程序暂停 5000 毫秒,也即 5 秒。

注意:sleep() 和 Sleep() 都不是C语言的标准函数,而是 Linux 和 Windows 自带的函数。也就是说,C语言本身并不支持它们,只有操作系统才支持它们。

编译并运行程序,会发现第一个 printf() 首先输出(程序运行后立即输出),等待 5 秒以后,第二个 printf() 才输出,请看下面的动画演示:

%title插图%num

在第一个 printf() 的最后添加一个换行符,情况也是一样的,第一个 printf() 从来不会和第二个 printf() 一起输出。

你看,Windows 和 Linux、macOS 的情况又不一样。这是因为,Windows 和 Linux、macOS 的缓存机制不同,Windows 下的 printf() 函数不带缓冲区。更加深入的内容,我们将在本章的《进入缓冲区(缓存)的世界,破解一切与输入输出有关的疑难杂症》中详细讲解。

要想破解 printf() 输出的问题,必须要了解缓存,它能使你对输入输出的认识上升到一个更高的层次,以后不管遇到什么疑难杂症,都能迎刃而解。可以说,输入输出的“命门”就在于缓存。

相关推荐: 二进制、八进制和十六进制详解(附带示意图)

在编程过程中,我们除了会使用十进制来表示数字,还会使用二进制、八进制和十六进制,它们在某些情况下比十进制更加直观。 我们平时使用的数字都是由 0~9 共十个数字组成的,例如 1、9、20、472、7023 等,一个数字最多能表示九,如果要表示十、十一、二十九、…

Tags: , ,