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

從零構建 C 語言輕量級配置檔解析庫

     編輯:關於C語言

專案背景與動機

在嵌入式或系統級開發中,JSON、XML 等重型格式往往過於龐大。本文展示如何從零開始,設計一個支援「`$key = "value"`」語法的極簡配置檔解析器,並將其封裝為可複用的 C 庫,提供 `sc_start()` 初始化與 `sc_get(key)` 取值兩大介面。

配置檔語法規範

$heoo = "Hello World\n";
$yexu = "\"你好嗎\", 我很好.謝謝!";
$end = "coding future 123 runing, ";
  • 以 `$` 開頭,後接變數名。
  • 等號 `=` 分隔鍵值,允許前後空白。
  • 值以雙引號 `"` 包裹,內部可用 `\"` 轉義引號。

核心解析演算法(有限狀態機)

  1. 跳過行首空白,尋找 `$`。
  2. 讀取鍵名直到 `=`,忽略空白。
  3. 跳過 `=` 後空白,尋找起始 `"`。
  4. 逐字讀取值內容,遇到 `"` 且前一字元非 `\` 判定結束。
  5. 將鍵值對存入字典,繼續處理下一行。

庫架構設計

公開介面:scconf.h

#ifndef _H_SCCONF
#define _H_SCCONF

#define _STR_SCCONF_PATH "module/schead/config/config.ini"

extern void sc_start(void);                 /* 初始化/重載 */
extern const char* sc_get(const char* key); /* 取值,失敗回傳 NULL */

#endif

內部資料結構:紅黑樹/二叉搜尋樹

struct dict {
    _TREE_HEAD;          /* 通用樹節點頭部 */
    char* key;
    char* value;
};

採用通用 `tree.h` 實現鍵值存儲,支援 O(log n) 查找。記憶體管理由 `tstring.h` 動態字串輔助,執行緒安全由 `scatom.h` 原子鎖保護。

關鍵實現片段

解析入口:__analysis_start

static void __analysis_start(FILE* txt, tree_t* proot) {
    char c, n;
    TSTRING_CREATE(tstr);  /* 動態字串建構器 */

    while ((c = fgetc(txt)) != EOF) {
        /* 1. 跳過空白 */
        while (c != EOF && isspace(c)) c = fgetc(txt);
        /* 2. 必須以 $ 開頭 */
        if (c != '$') { while (c != EOF && c != '\n') c = fgetc(txt); continue; }
        if ((c = fgetc(txt)) != EOF && isspace(c)) { while (c != EOF && c != '\n') c = fgetc(txt); continue; }

        tstr.len = 0;
        /* 3. 讀取 key 直到 = */
        while (c != EOF && c != '=') { if (!isspace(c)) tstring_append(&tstr, c); c = fgetc(txt); }
        if (c != '=') break;
        c = '\0';  /* key 結束標記 */

        /* 4. 跳過空白找起始 " */
        while (c != EOF && c != '"') { if (!isspace(c)) tstring_append(&tstr, c); c = fgetc(txt); }
        if (c != '"') break;

        /* 5. 讀取 value 直到未轉義的 " */
        for (n = c; (c = fgetc(txt)) != EOF; n = c) {
            if (c == '"' && n != '\\') break;
            tstring_append(&tstr, c);
        }
        if (c != '"') break;

        tree_add(proot, &tstr);  /* 將 key\0value 串存入樹 */

        /* 6. 讀完行尾 */
        while (c != EOF && c != '\n') c = fgetc(txt);
        if (c != '\n') break;
    }
    TSTRING_DESTROY(tstr);
}

公開 API 實現

void sc_start(void) {
    FILE* txt = fopen(_STR_SCCONF_PATH, "r");
    if (!txt) { SL_NOTICE("fopen config error"); return; }

    ATOM_LOCK(__lock);
    __tds_destroy();  /* 釋放舊樹 */
    __tds = tree_create(__dict_new, __dict_acmp, __dict_gdcmp, __dict_del);
    __analysis_start(txt, &__tds);
    ATOM_UNLOCK(__lock);
    fclose(txt);
}

inline const char* sc_get(const char* key) {
    struct dict* kv;
    if ((!key) || (!*key) || !(kv = tree_get(__tds, key, NULL))) return NULL;
    return kv->value;
}

使用示例

#include 
#include 

int main() {
    sc_start();
    puts(sc_get("heoo"));      /* Hello World */
    puts(sc_get("yexu"));      /* "你好嗎", 我很好.謝謝! */
    puts(sc_get("end"));       /* coding future 123 runing, */
    puts(sc_get("heoo2") ? : "heoo2不存在");
    return 0;
}

專案結構

目錄結構

總結與展望

本庫展示了「語法解析 + 字典資料結構 + 記憶體管理 + 執行緒安全」的完整工程化流程。後續可擴充支援:區塊、陣列、型別自動推導、熱重載通知等特性,逐步演進為生產級配置中心客戶端。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved