往期内容回顾
自动化构建工具-make/Makefile
gcc/g++编译及链接
Vim工具的使用
Linux常用工具(yum与vim)
Linux系统编程Day4-- Shell与权限
编写第一个Linux程序
今天我们要利用我们所学到的Linux语言来编译第一个Linux程序,在进行编写之前,我们首先要理解以下两个问题:
1、缓冲区问题
什么是缓冲区
-
缓冲区就是一块内存,用来临时存储数据,等满足某些条件再一次性读写。
-
在 C 语言和 Linux 中,printf、scanf、fgets 等函数并不是直接操作硬件,而是先把数据放到缓冲区,再由系统调用(write、read)发送/接收。
为什么要有缓冲区
-
效率:硬件 IO 操作(如磁盘、终端)很慢,如果每个字符都直接写到终端,速度很低。
-
减少系统调用次数:批量处理数据比一次一次调用 write() 更高效。
缓冲区的类型
Linux 中标准输入输出有三种缓冲模式:
缓冲模式 | 特点 | 典型场景 |
---|---|---|
全缓冲(Fully buffered) | 缓冲区满了才输出 | 文件 IO |
行缓冲(Line buffered) | 遇到换行符 \n 或缓冲区满才输出 | 终端 IO |
无缓冲(Unbuffered) | 直接输出,不用缓冲区 | stderr |
举个例子
#include<stdio.h> #include<unistd.h>int main(){printf("You can see me !--------");// 没有换行,不会立即显示sleep(3); // 系统休眠3sreturn 0; }
这里我们写了一个这样的程序,printf中没有换行符,当运行程序时:
不会立马输出printf中的内容,而是先休眠3s在输出。
原因:
在终端运行时,你可能看不到 "You can see me",因为printf先把数据放到缓冲区,再由系统调用,导致系统先休眠了,等休眠解释之后在由标准输出。
如何解决这个问题呢?
在 printf 后加 \n(行缓冲会触发刷新)
手动 fflush(stdout);
2、回车换行
概念区别
-
回车(Carriage Return,CR,\r):光标回到行首(但不换行)
-
换行(Line Feed,LF,\n):光标移动到下一行(但不回到行首)
-
历史原因:打字机时代是两个独立动作,后来延续到了计算机。
不同系统的表示
系统 | 换行符号 | ASCII 表示 |
---|---|---|
Linux / macOS | \n | LF (0x0A) |
Windows | \r\n | CR+LF |
旧版 Mac (pre-OSX) | \r | CR (0x0D) |
为什么要理解
-
跨平台差异:Windows 文本文件带 \r\n,Linux 用 \n,直接用 cat 或 vi 可能多出 ^M。
-
输入读取行为:终端输入时按下回车,Linux 会发送 \n,Windows 会发送 \r\n。
-
缓冲区刷新的触发:行缓冲模式下,遇到 \n 会触发刷新。
总结
-
缓冲区决定了输出什么时候真正显示(影响程序交互和性能)。
-
回车换行决定了不同系统下文本和输入输出的表现(影响跨平台兼容性)。
-
在写 Linux 程序时,这两个问题会直接影响输出顺序、数据同步、终端交互。
3、进度条程序的实现
#include <iostream> #include <iomanip> // std::setw #include <unistd.h> // sleep using namespace std;void showProgressBar(int total, int current) {const int barWidth = 50; // 进度条长度float progress = (float)current / total;int pos = (int)(barWidth * progress);cout << "[";for (int i = 0; i < barWidth; ++i) {if (i < pos) cout << "=";else if (i == pos) cout << ">";else cout << " ";}cout << "] ";// 输出百分比,宽度3,右对齐cout << setw(3) << (int)(progress * 100) << "% ";// 输出倒计时秒数cout << "(" << (total - current) << "s left)" << "\r" << flush; }int main() {int totalSeconds = 10;for (int i = 0; i <= totalSeconds; ++i) {showProgressBar(totalSeconds, i);sleep(1);}cout << endl; // 结束时换行return 0; }
说明:
-
使用了 \r(回车)使光标回到行首,实现刷新覆盖输出。
-
用 flush 刷新输出缓冲区,确保进度条及时显示。
-
进度条长度固定为50,随时间更新,视觉效果流畅。
-
显示百分比和剩余秒数,清晰易懂。