Linux的小程序——進度條

為了寫出這個小程序我們先來了解幾個知識點


(一)回車和換行

先以寫作文為例子了解一下,當在一行中寫了一半,由此處位置往下一行的操作叫做換行,回到該行的開頭位置為回車。

而在c語言中\n幫我們完成了換行和回車兩個動作,那單純回車是——\r


(二)緩沖區概念

#include <stdio.h>
#include <unistd.h>int main()
{printf("hello world\n");sleep(3);return 0;
}

在LInux中如何查看sleep,man sleep即可

有什么現象:

即先打印hello world在休眠三秒

#include <stdio.h>
#include <unistd.h>int main()
{printf("hello world");sleep(3);return 0;
}

現象如下:

看到的是他是先休眠了,在打印的。那他的順序真的是這樣的嗎?
不對,在 C 語言中,printf("hello world") 先執行,但輸出內容會被暫存在標準輸出緩沖區(stdout 緩沖區) 中,并未立即顯示到屏幕。隨后執行 sleep(3) 進行休眠,3 秒后程序結束時,緩沖區會被自動刷新,內容才顯示出來。這就是為什么看起來像是 “先休眠再打印” 的原因。

為什么需要緩沖區?

標準輸出(stdout)默認是行緩沖模式

  • 當輸出內容包含換行符 \n 時,會自動刷新緩沖區
  • 若沒有換行符,會積累到一定大小(通常是 4096 字節)或程序結束時才刷新

代碼中 printf 沒有換行符,因此內容暫存在緩沖區,直到程序結束才輸出,中間被 sleep(3) 打斷,造成了執行順序的 “錯覺”。

那如果我要強制刷新怎么辦了?

先了解C語言程序中默認會打開3個輸入輸出流,即標準輸入,標準輸出,標準錯誤。標準輸出為顯示器(stdout),其中Liunx下一切皆文件,那顯示器也是文件。
可以用 fflush 函數手動刷新指定流,立即輸出緩沖區內容:

#include <stdio.h>
#include <unistd.h>  // 包含sleep函數的頭文件int main()
{printf("hello world");fflush(stdout);  // 強制刷新標準輸出緩沖區sleep(3);        return 0;
}

此時現象:

?為了看起來更順眼我們可以在后面加一個換行。

又有上面的知識點我們可以寫一個倒計時

#include <stdio.h>
#include <unistd.h>int main()
{int cut=10;while(cut>=0){printf("%-2d\r",cut);fflush(stdout);cut--;sleep(1);}printf("\n");return 0;
}

運行結果:

細節解釋:

printf("%-2d\r",cut)為什么是%-2d

因為輸入10,顯示器會將它顯示成1 0

但是我們要的就是10,所以要寫成%2d,%2d是指定整數輸出時至少占用 2 個字符寬度,但是c語言進行輸出顯示,默認是右對齊,所以要用%-2d,-符合是強制左對齊。

?\r的作用

回車符,光標回到行首

總結:

  • 每次輸出時,%-2d 確保無論數字是一位還是兩位,都占用固定的 2 個字符位置。
  • 左對齊的補空格方式,能保證光標回到行首后,新數字會完全覆蓋上一次的輸出(不會留下殘留字符)。

(三)進度條的實現?

(1)?準備工作

依舊使用多文件,建立一個processbar.h,processbar.c ,test.c

其中processbar.c ,test.c包含processbar.h

(2)?實現

1. processbar.h代碼:

#pragma once
#include <stdio.h>#define NUM 102
#define STYLE '#'extern void processbar();

小細節:

1.1 extern void processbar();

這里的extern聲明表示processbar()函數在其他文件中定義,當前文件僅作聲明。在單個模塊(單文件)中確實可以省略,但在多文件項目中,使用extern可以清晰地表明這是一個外部函數,增強代碼的可讀性和規范性

1.2. #define NUM 102

保證每次輸出的字符比上次多,定義一個數組,其中NUM為數據開辟的空間,使用宏定義方便統一修改,且可以避免在代碼中硬編碼數值,提高可維護性。

1.3. #define STYLE '#'

定義進度條的顯示字符,因為風格多變,當需要改變進度條樣式時,只需修改這一處定義即可
增強了代碼的靈活性

?2. test.c代碼:

調用這個小程序

#include "processbar.h"
#include <unistd.h>int main()
{processbar();return 0;
}

3. processbar.c程序:

#include "processbar.h"
#include<string.h>
#include<unistd.h>const char* lable="|/-\\-";//這個加載的那個圈圈void processbar()
{char bar[NUM];memset(bar,'\0',sizeof(bar));//初始化數組int cnt=0;while(cnt<=100){printf("[%-100s][%d%%][%c]\r",bar,cnt,lable[cnt%5]);fflush(stdout);//強制刷新輸出緩沖區,確保進度條實時顯示bar[cnt++]=STYLE;usleep(100000);}printf("\n");
}

運行結果:?

小細節:

3.1. const char* b="|/-\\-";

定義了一個字符數組,包含幾個特殊字符,用于實現進度條前的 "旋轉加載" 效果(類似轉圈動畫)。這里的\\是轉義字符,表示一個反斜杠。

3.2. usleep

Linux 系統中用于暫停程序執行的函數,聲明在<unistd.h>頭文件中。

作用:

讓當前進程暫停指定的微秒數(1 微秒 = 1/1000000 秒)

3.3.?"[%-100s][%d%%][%c]\r"

  • [%-100s]:左對齊的 100 字符寬度區域,顯示當前進度
  • [%d%%]:顯示當前百分比,%%是轉義字符,表示%
  • [%c]:顯示旋轉動畫字符
  • \r:回車符,使光標回到行首,實現覆蓋輸出效果

4. makefile文件:

processbar:processbar.c test.c@gcc -o $@ $^
.PHONY:	clean
clean:rm -f processbar

小細節:

?4.1processbar:processbar.c test.c

  • 這是一個規則,processbar 是目標(可執行文件),processbar.c 和 test.c 是依賴文件
  • 意思是:要生成 processbar 這個可執行文件,需要先有 processbar.c 和 test.c 這兩個源文件
  • 多依賴文件之間用空格隔開

4.2@gcc -o $@ $^

  • @表示執行命令時不在終端顯示該命令本身
  • $@ → 目標文件名(要生成的結果)
  • $^ → 所有依賴的源文件(用來生成目標的原材料)

4.3.PHONY:?? ?clean

  • 聲明 clean 是一個偽目標(不是實際的文件)
  • 作用是避免當前目錄下有同名文件 clean 時,導致該規則失效

(3)進度條的調式和優化

上述進度條存在一定缺陷:

1.功能封裝不合理,復用性差

  • 進度條邏輯與控制強耦合:用戶無法根據實際場景(如下載、解壓等不同任務)控制進度條的更新時機和速度,只能被動執行函數內置的固定節奏。
  • 無法適配實際業務場景:實際開發中,進度條的更新應與任務進度(如下載字節數、處理數據量)綁定,而初始代碼的進度完全由函數內部的 cnt 自增控制,與真實任務進度脫節,用戶無法通過外部參數傳遞實際進度。

2. 擴展性差,難以二次使用

  • 單次使用限制:初始代碼中,processbar() 函數的進度條狀態(數組 bar)是局部變量,每次調用函數都會重新初始化并執行一次完整的進度條動畫。這導致它只能正確運行一次,若用戶需要在程序中多次顯示進度條(如多個任務依次執行),必須重新調用函數,但函數內部邏輯固定,無法重置或復用狀態。

3. 用戶交互設計不合理

  • 參數缺失,用戶體驗差:用戶使用時,只能調用 processbar() 函數執行一個固定的進度動畫,無法傳遞實際任務的總進度(如 “總大小 1000MB,當前下載 500MB”),導致進度條與真實任務無關,僅為一個 “虛假動畫”。
  • 狀態不透明:用戶無法知道進度條當前的實際進度(如百分比),只能被動等待動畫結束,缺乏對任務進度的感知。

4. 細節實現的局限性

  • 局部變量導致狀態無法延續:進度條的字符數組 bar是 processbar() 函數的局部變量,每次函數調用都會重新初始化,因此無法在多次調用中保留進度狀態,導致無法實現 “分階段更新進度”(如每次調用更新 10%)。

為了解決這個問題我將代碼進行了完善,我想要解決上面問題和形成如下進度條:

processbar.h

#pragma once
#include <stdio.h>#define NUM 102
#define TOP 100
#define STYLE '='
#define end '>'extern void processbar(int rate);
extern void Initbar();

processbar.c

#include "processbar.h"
#include<string.h>
#include<unistd.h>const char* lable="|/-\\-";
char bar[NUM];#define GREEN "\033[0;32;32m"
#define END "\033[m"void processbar(int rate)
{if(rate<0||rate>100)return;int len=strlen(lable);printf(GREEN"[%-100s]"END"[%d%%][%c]\r",bar,rate,lable[rate%len]);fflush(stdout);bar[rate++]=STYLE;if(rate<100)bar[rate]=end;
}void Initbar()
{//清空為'\0',避免首次使用時的隨機亂碼memset(bar,'\0',sizeof(bar));
}

小細節:

1.void Initbar()函數

用來解決擴展性差,難以二次使用問題,在調用進度條之前先調用這個函數。此時在processbar.h中也得進行聲明。

2.void processbar(int rate)
接收 rate 參數(0~100 的百分比),進度由外部傳入,調用者可根據實際場景(如下載了 30%)靈活控制顯示內容。

3.全局數組 char bar[NUM]

配合 Initbar() 初始化函數。數組生命周期與程序一致,進度狀態可跨多次 processbar() 調用累積,支持多次任務(例如連續下載多個文件時,每次調用 Initbar() 重置即可)。

4.#define GREEN "\033[0;32;32m"和#define END "\033[m"

ANSI 顏色控制宏:設置綠色文本,END用于恢復默認顏色

這些是博主搜的顏色替換,大家可以自己選然后改變

ANSI 顏色控制碼 - 前景色
#define FG_BLACK ? "\033[30m" ? // 黑色
#define FG_RED ? ? "\033[31m" ? // 紅色
#define FG_GREEN ? "\033[32m" ? // 綠色
#define FG_YELLOW ?"\033[33m" ? // 黃色
#define FG_BLUE ? ?"\033[34m" ? // 藍色
#define FG_MAGENTA "\033[35m" ? // 洋紅色
#define FG_CYAN ? ?"\033[36m" ? // 青色
#define FG_WHITE ? "\033[37m" ? // 白色

ANSI 顏色控制碼 - 背景色
#define BG_BLACK ? "\033[40m" ? // 黑色背景
#define BG_RED ? ? "\033[41m" ? // 紅色背景
#define BG_GREEN ? "\033[42m" ? // 綠色背景
#define BG_YELLOW ?"\033[43m" ? // 黃色背景
#define BG_BLUE ? ?"\033[44m" ? // 藍色背景
#define BG_MAGENTA "\033[45m" ? // 洋紅色背景
#define BG_CYAN ? ?"\033[46m" ? // 青色背景
#define BG_WHITE ? "\033[47m" ? // 白色背景

test.c

#include "processbar.h"
#include <unistd.h>typedef void (*callback_t)(int);void downLoad(callback_t cb)
{int total=1000;int curr=0;while(curr<=total){usleep(100000);int rate=curr*100/total;cb(rate);curr+=10;}printf("\n");
}int main()
{Initbar();downLoad(processbar);return 0;
}

小細節:

1. typedef void (*callback_t)(int);

是 C 語言中定義函數指針類型的語法

作用:給一個 “參數為 int、返回值為 void 的函數指針” 起一個別名 callback_t,簡化函數指針的使用

具體解釋:

void (*)(int):這是一個函數指針的 “原型”,表示:

  • 指向的函數返回值為 void(無返回值)。
  • 指向的函數接收一個 int 類型的參數。

callback_t:這是我們給這個函數指針類型起的別名。

運行結果:


以上就是進度條的知識點了,后續的完善工作我們將留待日后進行。希望這些知識能為你帶來幫助!如果覺得內容實用,歡迎點贊支持~ 若發現任何問題或有改進建議,也請隨時與我交流。感謝你的閱讀!?????

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/91220.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/91220.shtml
英文地址,請注明出處:http://en.pswp.cn/web/91220.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

在macOS上使用VS Code和Clang配置C++開發環境

本文基于VS Code官方文檔&#xff0c;詳細介紹如何在macOS系統下配置Clang/LLVM編譯器與VS Code的C開發環境。通過本文&#xff0c;你將學會如何搭建開發環境、創建并調試C程序&#xff0c;適合C初學者和需要在macOS上進行C開發的開發者。 前提條件 在開始配置前&#xff0c;…

Ganttable 基于工時的進度分析

時間進度分析是 Ganttable 提供的高級進度管理功能&#xff0c;它基于實際工作時長&#xff0c;結合計劃預估工時&#xff0c;可精準計算項目及任務的完成度。開啟進度分析開啟進度分析功能的操作如下&#xff1a;在時間管理頁面&#xff0c;點擊右上角的 “設置” 按鈕&#x…

duiLib 自定義資源目錄

前面的demo&#xff0c;把布局文件放在默認目錄了&#xff0c;想著應該也可以自定義資源路徑。先debug看下默認目錄是什么路徑。設置調試選項&#xff0c;調試信息格式改為程序數據庫&#xff08;/Zi&#xff09;再調試項目&#xff0c;選中監視1&#xff1a;在監護窗口中查看變…

YOLO-01目標檢測基礎

1、概念目標檢測&#xff08;Object Detection&#xff09;是計算機視覺中的一個重要領域&#xff0c;它涉及到識別圖片或視頻某一幀中的物體是什么類別&#xff0c;并確定它們的位置。通常用于多個物體的識別&#xff0c;可以同時處理圖像中的多個實例&#xff0c;并為每個實例…

Linux->動靜態庫

目錄 引入&#xff1a; 一&#xff1a;動靜態庫的介紹 1&#xff1a;庫的本質 2&#xff1a;庫的類別及優缺點 3&#xff1a;動態鏈接 4&#xff1a;靜態鏈接 二&#xff1a;頭文件和庫的查找 三&#xff1a;靜態庫的制作和使用 1&#xff1a;制作 2&#xff1a;指令打…

【LY88】雙系統指南及避坑

一. Windows重裝&#xff08;前提是Windows可正常使用&#xff0c;優點是無需U盤&#xff09; 1. PE工具和系統鏡像 機械師只只提供的資源鏈接 完成微PE工具的安裝并下載了系統鏡像之后&#xff0c;&#xff08;如果要裝ubuntu的話&#xff09;需確認磁盤分區格式和引導項。前…

Ubuntu22.04.1搭建php運行環境

步驟 1: 更新你的系統 首先&#xff0c;確保你的系統是最新的。打開終端并運行以下命令&#xff1a; sudo apt update sudo apt upgrade步驟 2: 安裝Apache Web服務器 使用Apache作為你的Web服務器。運行以下命令&#xff1a; sudo apt install apache2安裝完成后&#xff0c;你…

防止飛書重復回調通知分布式鎖

## 場景銷售訂單下&#xff0c;明細25明細款&#xff0c;發起飛書審批&#xff0c;飛書設置自動審核通過&#xff0c;導致會收到兩次審核通過通知加了分布式鎖 &#xff0c;仍導致執行業務執行兩遍了String lockKey "feihsu-approvalNotify:" instanceCode; RLock …

數據結構:下三角矩陣(Lower Triangular Matrix)

目錄 什么是下三角矩陣&#xff1f; 我們要存哪些元素&#xff1f;一共幾個&#xff1f; 推導索引映射公式 核心問題&#xff1a;給定 (i,j)&#xff0c;如何計算 k&#xff1f; 什么是下三角矩陣&#xff1f; 一個 n n 的矩陣&#xff0c;如果它在主對角線以上的所有元…

力扣209:長度最小的子數組

力扣209:長度最小的子數組題目思路代碼題目 給定一個含有 n 個正整數的數組和一個正整數 target 。 找出該數組中滿足其總和大于等于 target 的長度最小的 子數組 [numsl, numsl1, …, numsr-1, numsr] &#xff0c;并返回其長度。如果不存在符合條件的子數組&#xff0c;返回…

采購管理系統哪家性價比高?

在企業數字化轉型進程中&#xff0c;采購管理系統已成為降本增效的核心工具。但面對市場上五花八門的產品&#xff0c;“性價比” 成為企業選型時的關鍵考量 —— 既要功能貼合業務需求&#xff0c;又要成本可控&#xff0c;還需兼顧實施效率與長期擴展性。以下從性價比維度解析…

輕松打造Unity小游戲AR體驗

目錄 AR會話初始化 平面追蹤與相機定位 用戶交互處理 實時渲染 Unity 小游戲宿主現已支持 AR 功能&#xff0c;本文介紹如何從零開始創建一個可以在Unity小游戲宿主上運行的AR小游戲&#xff0c;歡迎大家試用&#xff01; 想為你的小游戲注入虛實交融的魔力嗎&#xff1f;…

IFCVF驅動+vhost-vfio提高虛擬機網絡性能

??IFCVF (Intel FPGA Virtual Function)?? 是 Intel 為其基于 FPGA 的智能網卡開發的 ??SR-IOV 虛擬功能驅動??,屬于 ??PF4 (Physical Function 4)?? 架構的一部分。它是專為高性能網絡虛擬化場景設計的硬件加速解決方案。 云計算智能網卡(soc)或DPU場景下,IFC…

Hook捕獲并攔截文件創建行為

需要用到minhook 先編譯DLL #include <Windows.h> #include <string> #include <TlHelp32.h> #include <Shlwapi.h>#include "MinHook.h" // 自動選擇正確的MinHook庫 #pragma comment(lib, "Shlwapi.lib") #if defined(_M_X64) …

圖像平滑處理

圖像平滑處理四種常用方式1. 均值濾波 (cv2.blur())2. 高斯濾波 (cv2.GaussianBlur())3. 中值濾波 (cv2.medianBlur())4、雙邊濾波 (cv2.bilateralFilter())總結存圖時遇到一個中文版亂碼問題四種常用方式 平滑處理&#xff08;也稱為模糊處理&#xff09;&#xff0c;用于減少…

fortigate的waf功能

在系統管理----可見功能----web應用防火墻打開waf功能Web 應用程序防火墻 &#xff08;WAF&#xff09; 配置文件可以檢測和阻止已知的 Web 應用程序攻擊。您可以將 WAF 配置文件配置為使用簽名和約束來檢查 Web 流量。您還可以強制實施 HTTP 方法策略&#xff0c;該策略控制與…

AI Compass前沿速覽:可靈創意工坊、字節Coze StudioCoze Loop、通義萬相2.2 、智譜GLM-4.5、騰訊混元3D世界模型開源

AI Compass前沿速覽&#xff1a;可靈創意工坊、字節Coze Studio&Coze Loop、通義萬相2.2 、智譜GLM-4.5、騰訊混元3D世界模型開源 AI-Compass 致力于構建最全面、最實用、最前沿的AI技術學習和實踐生態&#xff0c;通過六大核心模塊的系統化組織&#xff0c;為不同層次的學…

SpringCloud之Gateway

SpringCloud之Gateway 官網地址&#xff1a; https://docs.spring.io/spring-cloud-gateway/docs/current/reference/html/#gateway-request-predicates-factories 1. 什么是gateway Spring Cloud Gateway 是Spring Cloud官方推出的第二代網關框架&#xff0c;定位于取代 Net…

關于獲取某目錄及子目錄下所有文件且不包含隱藏文件

最近比較忙&#xff0c;很少寫blog了&#xff01;&#xff01;&#xff01;關于獲取目錄及子目錄下所有文件是常遇到的功能&#xff0c;一般通過遞歸遍歷實現。而生產場景中&#xff0c;一般是遍歷nas上的目錄&#xff0c;在nas上利用File.listFiles(),在linux系統上無法獲取含…

docker可視化管理工具lazydocker

Lazydocker 是一個用 Go 語言編寫的命令行 Docker 管理工具。它提供了一個簡潔、直觀的終端界面&#xff0c;支持鍵盤和鼠標操作&#xff0c;可通過方向鍵與快捷鍵實時查看和管理容器、鏡像、網絡等資源&#xff0c;大幅簡化了原本復雜的命令行操作&#xff0c;提升操作效率。2…