首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

TSDK.H:C語言通用開發工具包頭文件詳解 (字符串、文件、隨機數、時間、端序)

     編輯:關於C語言

一個精簡實用的 C 語言通用工具庫頭文件設計解析

`TSDK.H` 是一個針對 C 語言常見開發場景(字符串處理、文件操作、隨機數、時間計算、端序檢測、日志記錄)封裝的輕量級頭文件庫。代碼風格乾淨、註釋完善、無第三方依賴,適合嵌入式、Windows/Linux 跨平台項目作為基礎設施層。本文逐模塊解析其設計細節與使用場景。

庫宏觀結構

TSDK.H
├── 編譯器適配層 (_Cdecl, DOS/非DOS SAY 宏)
├── 通用工具宏 (MAX, MIN, FATAL, VERSION, bool 類型別名)
├── 字符串處理 (skip_spaces, strim)
├── 隨機數生成 (t_random)
├── 文件操作 (copy_file, file_exist)
├── 日志記錄 (log_save)
├── 日期時間 (is_leap_year, which_day)
└── 端序檢測 (is_little_endian)

核心模塊深度解析

1. 編譯器適配與基礎宏

// 調用約定適配
#if __STDC__
# define _Cdecl
#else
# define _Cdecl cdecl
#endif

// 跨平台輸出宏
#ifndef DOS
# define SAY(x...) printf(x)   // GCC 可變參宏
#else
# define SAY(x) printf(x)      // 老式 MSVC 不支援可變參宏
#endif

// 安全極值宏 (帶括號防副作用)
#ifndef MAX
# define MAX(a,b) ((a)<(b)?(b):(a))
#endif
#ifndef MIN
# define MIN(a,b) ((a)<(b)?(a):(b))
#endif

// 致命錯誤退出宏 (do-while(0) 保證語句級語義)
#define FATAL(x) do { \
    printf("\n[-] PROGRAM ABORT : %s", x); \
    exit(1); \
} while(0)

// 類型別名
#define VERSION "1.0.0"
#define true 1
#define false 0
typedef char bool;  // C89 無 _Bool,用 char 模擬

2. 字符串處理:去首尾空白

// 跳過前導空白 (isspace 檢查空格、\t、\n、\r、\v、\f)
char *skip_spaces(const char *str) {
    while (isspace(*str)) ++str;
    return (char *)str;
}

// 雙向修剪空白 (就地修改,返回原指針)
char *strim(char *s) {
    s = skip_spaces(s);           // 去首部
    size_t size = strlen(s);
    if (!size) return s;
    char *end = s + size - 1;
    while (end >= s && isspace(*end)) end--;  // 找尾部非空白
    *(end + 1) = '\0';            // 截斷
    return s;
}

適用場景:配置文件解析、命令行參數清洗、網絡協議字段提取。**注意**:就地修改原緩衝區,調用前確保可寫。

3. 隨機數:區間均勻分布

// 返回 [a, b) 區間隨機整數 (含 a,不含 b)
int t_random(int a, int b) {
    if (a >= b) return -1;
    srand(time(NULL));  // 以當前時間播種
    return (rand() % (b - a)) + a;
}

缺陷警示:

  • **每次調用重置種子**:短時間內多次調用 `time(NULL)` 返回同值,導致生成同樣隨機數。**正確做法**:程序啟動時**一次性** `srand(time(NULL))`,此函數僅調用 `rand()`。
  • `rand() % N` 取模偏斜:`RAND_MAX` 不能被 `N` 整除時,分布不均。嚴格場景用拒絕采樣或 C++11 ``。
  • 線程不安全:`rand`/`srand` 為全局狀態。

4. 文件操作:二進制拷貝與存在性檢查

// 二進制文件拷貝 (逐字節 fgetc/fputc,簡單但低效)
bool copy_file(char *src, char *dst, int flag) {
    if (flag == 0 && file_exist(dst)) return false;  // flag=0 目標存在則不覆蓋
    FILE *fin = fopen(src, "rb"), *fout = fopen(dst, "wb");
    if (!fin || !fout) { if (fin) fclose(fin); if (fout) fclose(fout); return false; }
    int ch;
    while ((ch = fgetc(fin)) != EOF) fputc(ch, fout);
    fclose(fin); fclose(fout);
    return true;
}

// 文件存在性檢查 (access 系統調用)
bool file_exist(char *file) {
    return !access(file, 0);  // 存在返回 0,取反為 true
}

優化建議:大文件拷貝用 `fread`/`fwrite` 批量塊操作 (如 4KB/64KB),或平台特定 `sendfile`/`CopyFile` 系統調用避免用戶態拷貝。

5. 日志記錄:簡單追加寫入

bool log_save(char *log_file, char *err_msg) {
    FILE *p = fopen(log_file, "wb");  // "wb" 會截斷文件!建議 "ab" 追加
    if (!p) return false;
    fprintf(p, "[Err]: %s\n", err_msg);
    fclose(p);
    return true;
}

關鍵 Bug**:`fopen(log_file, "wb")` 以**寫入模式截斷**文件,每次調用只保留最新一條日志。**必須改為 `"ab"` (二進制追加)** 保留歷史記錄。

6. 日期時間:閏年判斷與年間第幾天

// 閏年規則:400年整除 或 (4年整除 且 非100年整除)
bool is_leap_year(int year) {
    return ((year % 100 == 0) && (year % 400 == 0)) ||
           ((year % 100 != 0) && (year % 4 == 0));
}

// 計算年內第幾天 (1-366)
int which_day(int year, int mon, int day) {
    static int mdays[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30}; // 索引1起
    int days = day;
    for (int i = 1; i < mon; ++i) days += mdays[i];  // 累加前置月份天數
    if (mon > 2 && is_leap_year(year)) ++days;       // 閏年且過了2月,+1
    return days;
}

優化點:`mdays` 可改為 `const`,循環起始 `i=1` 更符合月份直覺 (原碼 `i=0` 累加 `mdays[0]=0` 無傷大雅但不直觀)。

7. 端序檢測:聯合體技巧

bool is_little_endian(void) {
    union { int a; char b; } c;
    c.a = 1;           // 整數 1 在內存中:小端 01 00 00 00,大端 00 00 00 01
    return (c.b == 1); // 讀取最低位字節:小端為 1,大端為 0
}

應用場景:網絡通信 (網絡序大端) 與主機序轉換、二進制文件格式解析、跨平台數據序列化。現代代碼優先用 `` / `` `htons`/`ntohl` 等標準函數。

完整頭文件結構 (重點標註修正點)

#ifndef __TSDK_H__
#define __TSDK_H__

#include 
#include 
#include 
#include   // for exit, access
#include 

// ... 編譯適配、基礎宏 (同上) ...

// 函數聲明
bool _Cdecl copy_file(char *src, char *dst, int flag);
bool _Cdecl file_exist(char *file);
char *_Cdecl skip_spaces(const char *str);
char *_Cdecl strim(char *p);
int _Cdecl t_random(int a, int b);
bool _Cdecl log_save(char *log_file, char *err_msg);
bool _Cdecl is_leap_year(int year);
int _Cdecl which_day(int year, int mon, int day);
bool _Cdecl is_little_endian(void);

// ... 函數定義 (建議移至 .c 文件,頭文件僅聲明) ...

#endif // __TSDK_H__

總結與改進路線圖

`TSDK.H` 展示了 C 語言構建輕量基礎設施的典型模式:**宏適配差異、標準庫組合封裝、聯合體/位運算硬件特性利用**。作為學習參考優秀,生產使用需修復日志截斷、隨機數重播種等關鍵缺陷,並遵循「聲明與定義分離」工程規範。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved
模塊現狀建議改進
隨機數每次調用 srand分離 srand 初始化;提供 64位/浮點/非均勻分布
文件拷貝逐字節 fgetc/fputc批量 fread/fwrite;異步 I/O;進度回調
日志"wb" 截斷模式**修為 "ab" 追加**;日志級別;輪轉;線程安全
字符串就地修剪提供非修改版 `strim_copy`;Unicode 感知
時間基礎計算時區感知;ISO8601 解析/格式化
架構頭文件含定義**拆分 .h/.c**;隱藏內部符號;單元測試