利用C語(yǔ)言編寫一個(gè)十六進(jìn)制日志轉(zhuǎn)換工具
當(dāng)然可以!下面是對(duì)您提供的 C 程序 逐行添加詳細(xì)注釋,并附上整體功能說(shuō)明,幫助你徹底理解每一部分的作用。
整體功能總結(jié)
該程序用于 處理帶時(shí)間戳的十六進(jìn)制日志文件(如串口/調(diào)試日志),自動(dòng)跳過(guò)時(shí)間戳部分(如 15:00:30.625 - ),僅提取其后的合法十六進(jìn)制字節(jié)(如 AA 55 36...),并將其轉(zhuǎn)換為 C 語(yǔ)言風(fēng)格的十六進(jìn)制格式(如 0xAA 0x55 0x36...),輸出到一個(gè) .dat 文本文件中。
- 不生成二進(jìn)制文件,輸出仍是人類可讀的文本
- 嚴(yán)格丟棄時(shí)間戳,避免誤解析(如
15被當(dāng)作0x15)
帶詳細(xì)注釋的完整代碼
// 引入標(biāo)準(zhǔn)庫(kù):輸入輸出、內(nèi)存操作、字符串處理、字符類型判斷
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
// 函數(shù):將單個(gè)十六進(jìn)制字符('0'-'9', 'A'-'F', 'a'-'f')轉(zhuǎn)換為對(duì)應(yīng)的數(shù)值(0-15)
// 例如:'A' → 10, 'f' → 15, '3' → 3
// 若輸入非法字符(如 'G', 'Z', '@'),返回 -1
int hexCharToValue(char c) {
if (c >= '0' && c <= '9') return c - '0'; // 數(shù)字字符轉(zhuǎn)數(shù)值
if (c >= 'a' && c <= 'f') return c - 'a' + 10; // 小寫 a-f 轉(zhuǎn) 10-15
if (c >= 'A' && c <= 'F') return c - 'A' + 10; // 大寫 A-F 轉(zhuǎn) 10-15
return -1; // 非法字符
}
// 主函數(shù)
int main() {
// 定義文件指針,用于讀取輸入和寫入輸出
FILE *inputFile, *outputFile;
// 存儲(chǔ)用戶輸入的文件名(不含擴(kuò)展名)
char inputFileName[256], outputFileName[256];
// 存儲(chǔ)完整的帶擴(kuò)展名的文件路徑(預(yù)留一點(diǎn)額外空間防溢出)
char fullInputFileName[260], fullOutputFileName[260];
// 用于存儲(chǔ)從輸入文件讀取的每一行內(nèi)容
char line[4096]; // 支持非常長(zhǎng)的日志行
// 提示用戶輸入輸入文件名(不帶 .txt)
printf("請(qǐng)輸入輸入文件名(不含.txt): ");
scanf("%s", inputFileName); // 注意:不能包含空格
// 提示用戶輸入輸出文件名(不帶 .dat)
printf("請(qǐng)輸入輸出文件名(不含.dat): ");
scanf("%s", outputFileName);
// 構(gòu)造完整的輸入文件名:拼接 ".txt"
strcpy(fullInputFileName, inputFileName); // 先復(fù)制基礎(chǔ)名
strcat(fullInputFileName, ".txt"); // 再追加擴(kuò)展名
// 構(gòu)造完整的輸出文件名:拼接 ".dat"
strcpy(fullOutputFileName, outputFileName);
strcat(fullOutputFileName, ".dat");
// 以文本模式打開(kāi)輸入文件(只讀)
inputFile = fopen(fullInputFileName, "r");
if (!inputFile) { // 如果打開(kāi)失?。ㄎ募淮嬖?權(quán)限問(wèn)題等)
perror("無(wú)法打開(kāi)輸入文件"); // 打印系統(tǒng)錯(cuò)誤信息(如 "No such file")
return 1; // 退出程序,返回錯(cuò)誤碼
}
// 以文本模式創(chuàng)建/覆蓋輸出文件(只寫)
outputFile = fopen(fullOutputFileName, "w");
if (!outputFile) {
perror("無(wú)法創(chuàng)建輸出文件");
fclose(inputFile); // 關(guān)閉已打開(kāi)的輸入文件,避免資源泄漏
return 1;
}
// 行號(hào)計(jì)數(shù)器(可用于調(diào)試或日志)
int lineNumber = 0;
// 循環(huán)讀取輸入文件的每一行,直到文件結(jié)束
while (fgets(line, sizeof(line), inputFile)) {
lineNumber++;
// 在當(dāng)前行中查找分隔符 " - "
// strstr 返回首次出現(xiàn) " - " 的位置指針,若未找到則返回 NULL
char *pos = strstr(line, " - ");
if (!pos) {
// 如果當(dāng)前行沒(méi)有 " - ",說(shuō)明不是標(biāo)準(zhǔn)日志格式,跳過(guò)該行
continue;
}
// 計(jì)算十六進(jìn)制數(shù)據(jù)開(kāi)始的位置:跳過(guò) " - "(共3個(gè)字符:空格、減號(hào)、空格)
char *hexStart = pos + 3;
// 使用 strtok 按空白字符(空格、制表符、換行等)分割 hexStart 中的內(nèi)容
// 第一次調(diào)用傳入字符串,后續(xù)傳入 NULL
char *token = strtok(hexStart, " \t\r\n");
int first = 1; // 標(biāo)記是否是當(dāng)前行的第一個(gè)有效十六進(jìn)制值(用于控制空格)
// 循環(huán)處理每一個(gè)分割出的 token(即可能的十六進(jìn)制字節(jié)字符串)
while (token) {
// 只有當(dāng) token 長(zhǎng)度恰好為2,且兩個(gè)字符都是合法十六進(jìn)制字符時(shí)才處理
if (strlen(token) == 2 &&
hexCharToValue(token[0]) != -1 &&
hexCharToValue(token[1]) != -1) {
// 將兩個(gè)十六進(jìn)制字符組合成一個(gè)字節(jié):
// 高4位 = 第一個(gè)字符的值 << 4,低4位 = 第二個(gè)字符的值
int byteVal = (hexCharToValue(token[0]) << 4) | hexCharToValue(token[1]);
// 如果不是第一個(gè)值,先輸出一個(gè)空格(保證格式:0xAA 0x55 ...)
if (!first) {
fprintf(outputFile, " ");
}
// 以 "0xXX" 格式寫入輸出文件(%02X 表示兩位大寫十六進(jìn)制,不足補(bǔ)0)
fprintf(outputFile, "0x%02X", byteVal);
first = 0; // 標(biāo)記已輸出至少一個(gè)值
}
// 繼續(xù)獲取下一個(gè) token(strtok 內(nèi)部維護(hù)狀態(tài))
token = strtok(NULL, " \t\r\n");
}
// 如果當(dāng)前行成功解析出至少一個(gè)十六進(jìn)制值,則在行尾添加換行符
if (!first) {
fprintf(outputFile, "\n");
}
}
// 關(guān)閉文件,釋放資源
fclose(inputFile);
fclose(outputFile);
// 打印成功提示
printf(" 處理完成!已嚴(yán)格丟棄所有時(shí)間戳,僅保留 ' - ' 后的十六進(jìn)制數(shù)據(jù)。\n");
printf("結(jié)果保存至: %s\n", fullOutputFileName);
return 0; // 正常退出
}工具準(zhǔn)備清單
- 編譯器:安裝 GCC(Windows 可用 MinGW 或 WSL)
- 編輯器:VS Code + C/C++ 插件
- 終端:Git Bash(Windows)或 Terminal(Mac/Linux)
- 調(diào)試:學(xué)會(huì)用
printf打印中間變量(最簡(jiǎn)單有效?。?/li>
最后鼓勵(lì)
你現(xiàn)在的狀態(tài)非常好——不是從抽象語(yǔ)法開(kāi)始學(xué),而是從一個(gè)真實(shí)問(wèn)題出發(fā)。這種“做中學(xué)”的方式效率最高!
記?。好恳粋€(gè)資深程序員,都曾卡在 fopen 返回 NULL 的問(wèn)題上。
如果你愿意,我可以:
- 為每一章提供 精簡(jiǎn)筆記 + 練習(xí)題
- 給你一個(gè) 可交互的學(xué)習(xí)計(jì)劃表(帶打卡)
- 提供 log 轉(zhuǎn) bin 的完整進(jìn)階代碼
這是一份為你量身定制的 「以十六進(jìn)制日志解析器」為項(xiàng)目驅(qū)動(dòng)的C語(yǔ)言學(xué)習(xí)路線圖。整個(gè)路線緊密圍繞你的代碼展開(kāi),逐層深入,每個(gè)階段都有明確的實(shí)踐目標(biāo)。
階段一:夯實(shí)C語(yǔ)言基礎(chǔ)(1-2周)
章節(jié)1.1:開(kāi)發(fā)環(huán)境搭建與調(diào)試入門
目標(biāo):能編譯運(yùn)行你的代碼,并理解每一步執(zhí)行過(guò)程。
知識(shí)點(diǎn):GCC編譯命令、調(diào)試器GDB基礎(chǔ)、斷點(diǎn)、單步執(zhí)行、觀察變量
實(shí)踐任務(wù):
- 手動(dòng)編譯你的代碼:
gcc your_code.c -o hexparser -Wall -Wextra -g - 用GDB在
hexCharToValue函數(shù)入口設(shè)置斷點(diǎn),觀察'A'、'f'、'9'的轉(zhuǎn)換過(guò)程 - 在
strtok循環(huán)中設(shè)置斷點(diǎn),觀察每個(gè)token的拆分結(jié)果
關(guān)鍵技能:學(xué)會(huì)用調(diào)試器驗(yàn)證你的假設(shè),這是最高效的學(xué)習(xí)方式
章節(jié)1.2:C程序結(jié)構(gòu)解剖 —— 你的代碼是第一課
目標(biāo):徹底理解代碼骨架,能復(fù)述每行作用。
知識(shí)點(diǎn):#include預(yù)處理器、main函數(shù)簽名、返回值意義、注釋規(guī)范
實(shí)踐任務(wù):
- 刪除某個(gè)
#include,觀察編譯錯(cuò)誤信息(理解每個(gè)頭文件的作用) - 將
int main()改為void main(),觀察警告信息 - 在
main函數(shù)不同位置return不同的值(0, 1, 2),用echo $?查看退出碼
關(guān)聯(lián)代碼:你代碼中的#include、函數(shù)定義、返回值
章節(jié)1.3:數(shù)據(jù)類型與變量 —— 內(nèi)存的抽象
目標(biāo):理解你代碼中每個(gè)變量的內(nèi)存布局和大小。
知識(shí)點(diǎn):int、char、數(shù)組的本質(zhì)、sizeof運(yùn)算符
實(shí)踐任務(wù):
- 打印所有數(shù)組和變量的大?。?code>printf("line size: %zu\n", sizeof(line));
- 創(chuàng)建測(cè)試函數(shù),驗(yàn)證
char的取值范圍(-128~127)和無(wú)符號(hào)版本 - 理解你的代碼為什么用
int byteVal而不是char byteVal(防止溢出和位運(yùn)算提升)
關(guān)聯(lián)你的代碼:char line[4096]、int byteVal、FILE *
章節(jié)1.4:運(yùn)算符與表達(dá)式 —— 位運(yùn)算專項(xiàng)
目標(biāo):親手重寫并理解十六進(jìn)制轉(zhuǎn)換的核心邏輯。
知識(shí)點(diǎn):位移<<、按位或|、算術(shù)轉(zhuǎn)換、運(yùn)算符優(yōu)先級(jí)
實(shí)踐任務(wù):
拆解表達(dá)式:int byteVal = (hexCharToValue(token[0]) << 4) | hexCharToValue(token[1]);
為token[0] = 'A', token[1] = 'F'時(shí),在紙上畫出每一步的位變化
重寫hexCharToValue函數(shù),用switch-case代替if鏈(理解不同實(shí)現(xiàn))
手動(dòng)實(shí)現(xiàn)一個(gè)decCharToValue函數(shù),轉(zhuǎn)換十進(jìn)制字符'0'-'9'
核心洞察:位運(yùn)算是C高效處理底層數(shù)據(jù)的精髓
章節(jié)1.5:控制流 —— 代碼的決策邏輯
目標(biāo):畫出你代碼的執(zhí)行流程圖。
知識(shí)點(diǎn):if-else鏈、while循環(huán)、continue、break
實(shí)踐任務(wù):
- 為
main函數(shù)畫流程圖(包括文件打開(kāi)失敗、循環(huán)讀取、token處理分支) - 將
while(fgets(...))改造為do-while循環(huán),思考何時(shí)用哪種 - 在
strtok循環(huán)中添加break,測(cè)試在什么條件下跳出最合適
關(guān)聯(lián)代碼:if (!inputFile)、while (token)、if (strlen(token)==2)
階段二:字符串與內(nèi)存操作精講(2-3周)
章節(jié)2.1:字符操作深度實(shí)踐
目標(biāo):重寫并優(yōu)化hexCharToValue函數(shù)。
知識(shí)點(diǎn):ASCII碼表、ctype.h庫(kù)(isxdigit、tolower)、字符與數(shù)字關(guān)系
實(shí)踐任務(wù):
- 用標(biāo)準(zhǔn)庫(kù)重寫函數(shù):
if (isxdigit(c)) { return (isdigit(c) ? c-'0' : tolower(c)-'a'+10); } - 對(duì)比你的實(shí)現(xiàn)和標(biāo)準(zhǔn)庫(kù)實(shí)現(xiàn)的優(yōu)劣(依賴性、性能、可讀性)
- 擴(kuò)展:實(shí)現(xiàn)一個(gè)
valueToHexChar反向函數(shù)(0-15 → '0'-'F')
關(guān)鍵理解:字符在C中就是小整數(shù),'A'比'a'小32
章節(jié)2.2:字符串基礎(chǔ)與string.h全家桶
目標(biāo):從代碼出發(fā),掌握所有用到的字符串函數(shù)。
知識(shí)點(diǎn):strcpy、strcat、strstr、strlen、strtok的行為與陷阱
實(shí)踐任務(wù):
- 安全改造:將
strcpy(fullInputFileName, inputFileName)改為strncpy并手動(dòng)補(bǔ)\0 - 對(duì)比實(shí)驗(yàn):
strstrvs.strchr,用strchr(line, '-')能否替代strstr(line, " - ")? - strtok的坑:在一個(gè)循環(huán)中同時(shí)處理兩行數(shù)據(jù)(會(huì)失?。?,理解其靜態(tài)內(nèi)部狀態(tài)
- 內(nèi)存重疊實(shí)驗(yàn):用
strcpy復(fù)制重疊內(nèi)存區(qū)域,觀察未定義行為
必讀手冊(cè):man strtok時(shí)特別注意"WARNING"部分
章節(jié)2.3:字符串高級(jí)操作與內(nèi)存安全
目標(biāo):讓你的代碼健壯到能處理惡意輸入。
知識(shí)點(diǎn):緩沖區(qū)溢出、strncpy/snprintf、strnlen、防御性編程
實(shí)踐任務(wù):
- 算一筆賬:如果用戶輸入
inputFileName為255個(gè)字符,你的代碼會(huì)溢出嗎?(會(huì)!strcat后超256) - 重構(gòu):用
snprintf(fullInputFileName, sizeof(fullInputFileName), "%s.txt", inputFileName);替代strcpy+strcat - 防御:在
hexCharToValue開(kāi)頭加斷言:if (c == '\0') return -1; - 模糊測(cè)試:創(chuàng)建一個(gè)
.txt文件,包含超長(zhǎng)行、空行、" - "后無(wú)內(nèi)容、非法十六進(jìn)制字符,測(cè)試你的程序崩潰點(diǎn)
核心價(jià)值:C程序員的第一職責(zé)是保護(hù)內(nèi)存
章節(jié)2.4:十六進(jìn)制與字節(jié)流專項(xiàng)
目標(biāo):擴(kuò)展代碼,支持更多格式。
知識(shí)點(diǎn):十六進(jìn)制字符串、字節(jié)序、二進(jìn)制表示
實(shí)踐任務(wù):
- 支持前綴:修改代碼,能識(shí)別
0xAA、0Xbb、AAh等多種格式 - 反向操作:編寫一個(gè)
valueToHexString函數(shù),將字節(jié)數(shù)組轉(zhuǎn)為"AA BB CC"字符串 - 批量轉(zhuǎn)換:將輸出格式改為純二進(jìn)制文件(
fopen(..., "wb")+fwrite) - 計(jì)算器:寫一個(gè)命令行十六進(jìn)制計(jì)算器,輸入
1A + 2B,輸出45
關(guān)聯(lián)代碼:你的核心轉(zhuǎn)換邏輯是項(xiàng)目基石
章節(jié)2.5:緩沖區(qū)管理藝術(shù)
目標(biāo):徹底理解fgets(line, sizeof(line), inputFile)的邊界行為。
知識(shí)點(diǎn):fgets與gets的區(qū)別、緩沖區(qū)大小計(jì)算、行截?cái)嗵幚?/p>
實(shí)踐任務(wù):
- 超長(zhǎng)行測(cè)試:創(chuàng)建一個(gè)4097字符的行(不含
\n),觀察fgets行為(會(huì)截?cái)啵?/li> - 殘行處理:檢測(cè)到行被截?cái)鄷r(shí)(
strlen==4095且末位不是\n),如何繼續(xù)讀取剩余部分? - 內(nèi)存占用:嘗試將
line改為char *line = NULL; size_t len = 0;并用getline(&line, &len, inputFile)自動(dòng)分配 - 性能考量:對(duì)比固定緩沖區(qū) vs.
getline在處理1GB文件時(shí)的內(nèi)存和速度差異
關(guān)鍵理解:C中沒(méi)有"字符串類型",只有字符數(shù)組和指針約定
階段三:文件與I/O系統(tǒng)實(shí)戰(zhàn)(1-2周)
章節(jié)3.1:標(biāo)準(zhǔn)I/O流深度解析
目標(biāo):理解printf、scanf、fprintf的底層。
知識(shí)點(diǎn):stdin/stdout/stderr、緩沖區(qū)機(jī)制、格式字符串
實(shí)踐任務(wù):
- 重定向?qū)嶒?yàn):
./hexparser < input.txt > output.dat 2>error.log,觀察perror輸出到哪 - 格式控制:將
fprintf(outputFile, "0x%02X", byteVal);改為小寫%02x,再改為輸出十進(jìn)制%03d - scanf的坑:輸入文件名帶空格會(huì)怎樣?改用
scanf("%255s", ...)限制長(zhǎng)度 - 非交互模式:用
getenv("INPUT_FILE")環(huán)境變量替代scanf,實(shí)現(xiàn)無(wú)人值守批處理
關(guān)聯(lián)代碼:所有I/O函數(shù)都是FILE*操作的特例
章節(jié)3.2:文件操作API全掌握
目標(biāo):用多種方式重寫文件讀寫邏輯。
知識(shí)點(diǎn):fopen模式字符串、fclose必要性、perror與strerror
實(shí)踐任務(wù):
- 模式實(shí)驗(yàn):將
"r"改為"rb",在Windows和Linux下對(duì)比處理\r\n的差異 - 錯(cuò)誤細(xì)分:用
if (errno == ENOENT)判斷文件不存在,給出更友好的提示 - 返回值檢查:檢查
fprintf的返回值(寫入字符數(shù)),確保數(shù)據(jù)完整 - 原子寫入:寫入臨時(shí)文件,成功后
rename為最終文件名,防止程序崩潰產(chǎn)生半文件
關(guān)鍵習(xí)慣:每個(gè)系統(tǒng)調(diào)用后檢查返回值
章節(jié)3.3:文本處理管線模式
目標(biāo):模仿Unix工具鏈,讓程序更通用。
知識(shí)點(diǎn):管道、過(guò)濾器模式、行處理架構(gòu)
實(shí)踐任務(wù):
- Unix化改造:支持從
stdin讀取和寫入stdout,文件名留空時(shí)自動(dòng)切換 - 工具組合:
cat log.txt | ./hexparser | wc -c統(tǒng)計(jì)轉(zhuǎn)換后的字節(jié)數(shù) - 多格式輸出:增加命令行選項(xiàng)
-o bin輸出二進(jìn)制,-o c輸出C數(shù)組格式 - 日志輪轉(zhuǎn):處理多個(gè)輸入文件
*.txt,生成對(duì)應(yīng)*.dat
設(shè)計(jì)哲學(xué):一個(gè)好程序應(yīng)該能嵌入更大的流程
章節(jié)3.4:錯(cuò)誤處理與健壯性工程
目標(biāo):讓你的程序在極端環(huán)境下也不崩潰。
知識(shí)點(diǎn):錯(cuò)誤碼設(shè)計(jì)、資源清理(RAII模式)、斷言assert
實(shí)踐任務(wù):
- 資源泄漏檢測(cè):注釋掉
fclose,用valgrind ./hexparser檢測(cè)泄漏 - 異常路徑清理:在任意
return 1前確保所有已分配資源被釋放(用goto cleanup模式) - 輸入驗(yàn)證:在
hexCharToValue中,用assert(isxdigit(c))捕獲開(kāi)發(fā)期錯(cuò)誤 - 壓力測(cè)試:處理10萬(wàn)行、每行1MB的輸入文件,監(jiān)控內(nèi)存占用是否穩(wěn)定
最佳實(shí)踐:錯(cuò)誤處理代碼應(yīng)占30%以上
階段四:代碼重構(gòu)與進(jìn)階技術(shù)(2-3周)
章節(jié)4.1:指針進(jìn)階 —— 從數(shù)組到指針的躍遷
目標(biāo):將代碼中所有數(shù)組操作改為指針操作。
知識(shí)點(diǎn):數(shù)組名退化、ptr++、指針?biāo)阈g(shù)、const指針
實(shí)踐任務(wù):
- 指針化:將
line[0]訪問(wèn)改為*line,token[0]改為*token - 遍歷優(yōu)化:用
for(char *p = line; *p; p++)替代strtok,手動(dòng)分割token - const correctness:
const char *hexString作為輸入?yún)?shù),防止意外修改 - 函數(shù)指針:創(chuàng)建一個(gè)函數(shù)指針數(shù)組,支持多種解析格式(十六進(jìn)制、十進(jìn)制、二進(jìn)制)
核心理解:指針是C的靈魂,也是最大的風(fēng)險(xiǎn)源
章節(jié)4.2:動(dòng)態(tài)內(nèi)存管理
目標(biāo):擺脫固定大小緩沖區(qū)限制。
知識(shí)點(diǎn):malloc/free/realloc、sizeof陷阱、內(nèi)存泄漏
實(shí)踐任務(wù):
- 動(dòng)態(tài)行:用
getline替代固定line[4096],處理任意長(zhǎng)度行 - 動(dòng)態(tài)數(shù)組:將解析出的字節(jié)存入
malloc分配的數(shù)組,最后統(tǒng)一寫入 - 內(nèi)存泄漏實(shí)驗(yàn):故意不寫
free,用valgrind --leak-check=full觀察 - 緩沖區(qū)增長(zhǎng)策略:實(shí)現(xiàn)一個(gè)動(dòng)態(tài)字符串,自動(dòng)
realloc增長(zhǎng)(類似C++std::string)
關(guān)鍵原則:誰(shuí)malloc,誰(shuí)free;配對(duì)出現(xiàn)
章節(jié)4.3:模塊化與接口設(shè)計(jì)
目標(biāo):將代碼拆分為可復(fù)用的模塊。
知識(shí)點(diǎn):頭文件.h、實(shí)現(xiàn)文件.c、API設(shè)計(jì)、封裝
實(shí)踐任務(wù):
- 拆分解析器:創(chuàng)建
hex_parser.h和hex_parser.c,提供parse_hex_line(const char *line, uint8_t *output) - 拆文件模塊:創(chuàng)建
file_utils.h,封裝open_file_safely、write_hex_array等函數(shù) - 單元測(cè)試:為
hexCharToValue寫測(cè)試用例,覆蓋所有分支 - Makefile:編寫Makefile,支持
make、make clean、make test
工程意義:這是從"腳本"到"軟件"的轉(zhuǎn)變
章節(jié)4.4:性能優(yōu)化實(shí)戰(zhàn)
目標(biāo):處理GB級(jí)日志文件速度提升10倍。
知識(shí)點(diǎn):緩沖區(qū)大小調(diào)優(yōu)、mmap內(nèi)存映射、減少系統(tǒng)調(diào)用
實(shí)踐任務(wù):
- 基準(zhǔn)測(cè)試:用
time命令測(cè)試處理100MB文件的時(shí)間 - 批量I/O:將
fprintf改為sprintf到緩沖區(qū),每8192字節(jié)寫入一次 - mmap改造:用
mmap映射整個(gè)文件,指針遍歷替代fgets(進(jìn)階) - 并行化:用
pthreads多線程處理文件的不同段(超進(jìn)階)
優(yōu)化信條:先測(cè)量,再優(yōu)化;算法 > 實(shí)現(xiàn) > 編譯器
階段五:項(xiàng)目擴(kuò)展與工程化(持續(xù)進(jìn)行)
章節(jié)5.1:命令行工具化
目標(biāo):支持./hexparser -i input.log -o output.dat --format=binary。
知識(shí)點(diǎn):argc/argv、getopt_long、配置文件
擴(kuò)展項(xiàng)目:
- 支持通配符
./hexparser *.log - 支持從ZIP包中讀取文件(集成
libzip)
章節(jié)5.2:多格式支持
目標(biāo):成為通用十六進(jìn)制轉(zhuǎn)換工具。
擴(kuò)展項(xiàng)目:
- 支持Motorola S-record、Intel HEX格式
- 支持ASCII轉(zhuǎn)十六進(jìn)制:
./hexparser --reverse將0xAA 0xBB轉(zhuǎn)回AA BB - 支持校驗(yàn)和計(jì)算(Checksum, CRC32)
章節(jié)5.3:跨平臺(tái)與國(guó)際化
目標(biāo):在Windows/Linux/macOS無(wú)差別運(yùn)行。
知識(shí)點(diǎn):條件編譯_WIN32、Unicode路徑、編碼轉(zhuǎn)換
實(shí)踐:
- 用
#ifdef _WIN32處理路徑分隔符/vs\ - 支持UTF-8文件名(Windows下需
_wfopen)
章節(jié)5.4:測(cè)試與持續(xù)集成
目標(biāo):寫出一個(gè)"自信"的程序。
知識(shí)點(diǎn):?jiǎn)卧獪y(cè)試框架(Check/CUnit)、自動(dòng)化測(cè)試
實(shí)踐項(xiàng)目:
- 創(chuàng)建
test/目錄,覆蓋所有邊界條件 - 集成GitHub Actions,每次提交自動(dòng)測(cè)試
- 生成代碼覆蓋率報(bào)告:
gcov+lcov
學(xué)習(xí)進(jìn)度建議與檢查點(diǎn)
| 周數(shù) | 攻克章節(jié) | 產(chǎn)出物 | 自我檢測(cè) |
|---|---|---|---|
| 1 | 1.1-1.5 | 能調(diào)試代碼,畫出流程圖 | 不看代碼能復(fù)述hexCharToValue邏輯 |
| 2-3 | 2.1-2.5 | 代碼無(wú)緩沖區(qū)溢出隱患 | 用valgrind檢測(cè)零錯(cuò)誤 |
| 4 | 3.1-3.4 | 支持管道操作,錯(cuò)誤處理完善 | 輸入不存在的文件,輸出清晰錯(cuò)誤 |
| 5-6 | 4.1-4.4 | 模塊化代碼 + Makefile | make test通過(guò)所有用例 |
| 7+ | 5.x | 支持命令行參數(shù),處理GB文件 | 處理1GB文件內(nèi)存穩(wěn)定 < 10MB |
終極挑戰(zhàn)項(xiàng)目
用你積累的所有知識(shí),重寫本項(xiàng)目并滿足:
- 零警告編譯(
-Wall -Wextra -Werror) - 通過(guò)所有邊界測(cè)試(空文件、超長(zhǎng)行、惡意輸入)
- 處理1GB文件內(nèi)存占用<10MB,速度比原版快5倍
- 輸出同時(shí)支持文本
0xAA和二進(jìn)制兩種格式 - 有完整單元測(cè)試,覆蓋率>90%
當(dāng)你完成時(shí),你已經(jīng)是合格的C語(yǔ)言系統(tǒng)程序員了!
記住,C語(yǔ)言學(xué)習(xí)的唯一捷徑就是親手敲每一行代碼,用調(diào)試器看每一個(gè)變量的變化。你的這段代碼是絕佳的起點(diǎn),因?yàn)樗w了C語(yǔ)言90%的核心知識(shí)點(diǎn)。堅(jiān)持按路線圖實(shí)踐,3個(gè)月后你會(huì)感謝現(xiàn)在的自己!
到此這篇關(guān)于利用C語(yǔ)言編寫一個(gè)十六進(jìn)制日志轉(zhuǎn)換工具的文章就介紹到這了,更多相關(guān)C語(yǔ)言十六進(jìn)制日志轉(zhuǎn)換內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Qt將數(shù)據(jù)庫(kù)中的數(shù)據(jù)導(dǎo)出為html
這篇文章主要為大家詳細(xì)介紹了Qt如何實(shí)現(xiàn)將數(shù)據(jù)庫(kù)中的數(shù)據(jù)導(dǎo)出為html,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2024-12-12
C語(yǔ)言實(shí)現(xiàn)BMP轉(zhuǎn)換JPG的方法
這篇文章主要介紹了C語(yǔ)言實(shí)現(xiàn)BMP轉(zhuǎn)換JPG的方法,涉及C#圖片格式轉(zhuǎn)換的相關(guān)技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-07-07
C語(yǔ)言實(shí)現(xiàn)職工工資管理系統(tǒng)的示例代碼
這篇文章主要為大家詳細(xì)介紹了C語(yǔ)言如何實(shí)現(xiàn)職工工資管理系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-08-08
C語(yǔ)言中實(shí)現(xiàn)自定義數(shù)據(jù)類型的輸入輸出的方法和技巧
在 C 語(yǔ)言中,除了基本的數(shù)據(jù)類型(如整型、浮點(diǎn)型、字符型等),我們還經(jīng)常需要自定義數(shù)據(jù)類型來(lái)滿足特定的編程需求,所以本文給大家介紹了C語(yǔ)言中實(shí)現(xiàn)自定義數(shù)據(jù)類型的輸入輸出的方法和技巧,需要的朋友可以參考下2024-07-07
舉例講解C語(yǔ)言程序中對(duì)二叉樹(shù)數(shù)據(jù)結(jié)構(gòu)的各種遍歷方式
這篇文章主要介紹了舉例講解C語(yǔ)言程序中對(duì)二叉樹(shù)數(shù)據(jù)結(jié)構(gòu)的各種遍歷方式,先序中序后序二叉樹(shù)遍歷幾乎成了最老生常談的數(shù)據(jù)結(jié)構(gòu)基礎(chǔ)知識(shí),的朋友可以參考下2016-04-04
C++中用substr()函數(shù)消除前后空格的解決方法詳解
本篇文章是對(duì)C++中用substr()函數(shù)消除前后空格的方法進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下2013-05-05
C++實(shí)現(xiàn)簡(jiǎn)單貪吃蛇小游戲
這篇文章主要為大家詳細(xì)介紹了C++實(shí)現(xiàn)簡(jiǎn)單貪吃蛇小游戲,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-05-05
C語(yǔ)言冷門知識(shí)之你可能沒(méi)聽(tīng)過(guò)的柔性數(shù)組
柔性數(shù)組(Flexible Array)是引入的一個(gè)新特性,它允許你在定義結(jié)構(gòu)體時(shí)創(chuàng)建一個(gè)空數(shù)組,而這個(gè)數(shù)組的大小可以在程序運(yùn)行的過(guò)程中根據(jù)你的需求進(jìn)行更改特別注意的一點(diǎn)是:這個(gè)空數(shù)組必須聲明為結(jié)構(gòu)體的最后一個(gè)成員,并且還要求這樣的結(jié)構(gòu)體至少包含一個(gè)其他類型的成員2021-10-10

