在 Linux C 專案中管理配置參數,iniparser 是輕量、無依賴、API 友善的首選庫。本文涵蓋庫獲取、編譯安裝、INI 檔語法、核心 API 詳解、完整範例程式、編譯鏈接指令與實務最佳實踐。
# 1. 下載 (GitHub / 官網 / SourceForge) wget https://github.com/ndevilla/iniparser/archive/refs/tags/v4.1.tar.gz # 2. 解壓並編譯 tar -zxvf v4.1.tar.gz cd iniparser-4.1 make # 3. 產出檔案 # src/libiniparser.a 靜態庫 # src/libiniparser.so.0 動態庫 # src/dictionary.h 底層字典 API # src/iniparser.h 高層 INI 解析 API # 4. 安裝到系統 (可選) sudo cp src/libiniparser.* /usr/local/lib/ sudo cp src/*.h /usr/local/include/ sudo ldconfig
# 註解以 ; 或 # 開頭 ; 這是註解 [section_name] ; 區塊名,獨立一行,方括號包裹 key = value ; 鍵值對,等號兩側可有空格 name = "with spaces" ; 值可含空格,建議加引號 flag = true ; 布林值:true/false, yes/no, on/off, 1/0 port = 8080 ; 整數 rate = 3.14 ; 浮點數 ; 區塊作用域到下一個區塊或檔案結尾 ; 區塊不可巢狀 ; 區塊名、鍵名不區分大小寫 (庫內部轉小寫)
| 分類 | 函數 | 用途 |
|---|---|---|
| 載入/釋放 | dictionary *iniparser_load(const char *ininame) | 解析檔案,回傳字典物件 |
void iniparser_freedict(dictionary *d) | 釋放字典記憶體 | |
dictionary *iniparser_load_file(const char *ininame) | 別名 | |
int iniparser_save(dictionary *d, const char *ininame) | 寫回檔案 (v4 新增) | |
| 區塊操作 | int iniparser_getnsec(dictionary *d) | 取得區塊總數 |
char *iniparser_getsecname(dictionary *d, int n) | 取得第 n 個區塊名 | |
int iniparser_getsecnkeys(dictionary *d, char *section) | 取得區塊鍵總數 | |
| 取值 (類型安全) | char *iniparser_getstring(dictionary *d, const char *key, char *def) | 取字串,key 格式 "section:key" |
int iniparser_getint(dictionary *d, const char *key, int notfound) | 取整數 | |
double iniparser_getdouble(dictionary *d, const char *key, double notfound) | 取浮點數 | |
int iniparser_getboolean(dictionary *d, const char *key, int notfound) | 取布林 (1/0) | |
int iniparser_find_entry(dictionary *d, const char *key) | 檢查鍵是否存在 | |
| 修改/刪除 | int iniparser_set(dictionary *d, const char *entry, const char *val) | 設定/新增鍵值 |
void iniparser_unset(dictionary *d, const char *entry) | 刪除鍵 | |
void iniparser_dump(dictionary *d, FILE *out) | 除錯輸出完整字典 |
config.ini# TCP 連線設定 [tcp] port = 8000 ip = 127.0.0.1 family = AF_INET # 序列埠設定 [serial port] speed = 9600 parity = none
example.c#include <stdio.h>
#include <stdlib.h>
#include "iniparser.h"
int main() {
dictionary *ini = iniparser_load("config.ini");
if (ini == NULL) {
fprintf(stderr, "無法開啟 config.ini\n");
return EXIT_FAILURE;
}
// 除錯:印出完整字典
iniparser_dump(ini, stderr);
// 讀取 tcp 區塊
printf("%s: \n", iniparser_getsecname(ini, 0));
int port = iniparser_getint(ini, "tcp:port", -1);
printf("port: %d\n", port);
char *ip = iniparser_getstring(ini, "tcp:ip", NULL);
printf("ip: %s\n", ip);
char *family = iniparser_getstring(ini, "tcp:family", NULL);
printf("family: %s\n", family);
// 讀取 serial port 區塊 (含空格)
printf("%s: \n", iniparser_getsecname(ini, 1));
int speed = iniparser_getint(ini, "serial port:speed", -1);
printf("speed: %d\n", speed);
iniparser_freedict(ini);
return 0;
}
gcc example.c -o example -L. -liniparser # 或指定完整路徑 gcc example.c -o example -I/usr/local/include -L/usr/local/lib -liniparser # 執行 ./example
dictionary obj: [tcp]=UNDEF [tcp:port]=[8000] [tcp:ip]=[127.0.0.1] [tcp:family]=[AF_INET] [serial port]=UNDEF [serial port:speed]=[9600] tcp: port: 8000 ip: 127.0.0.1 family: AF_INET serial port: speed: 9600
iniparser_set(ini, "tcp:port", "9000"); iniparser_save(ini, "config.ini"); // v4+ 支援
iniparser_getint(ini, "tcp:timeout", 30) 找不到回傳 30。true/false, yes/no, on/off, 1/0 自動轉換。TCP:PORT、tcp:port 等效。iniparser_load 分配,iniparser_freedict 釋放,嚴格配對。| 庫 | 語言 | 特點 | 依賴 | 授權 |
|---|---|---|---|---|
| iniparser | C | 輕量、無依賴、API 簡潔 | 無 | MIT |
| libconfini | C | 支援巢狀區塊、Schema 驗證 | 無 | LGPL |
| inih | C | 單檔案、極輕量、回調式 | 無 | BSD |
| GKeyFile (GLib) | C | 功能豐富、GLib 生態 | GLib | LGPL |
| Boost.Program_options | C++ | 型別安全、命令列整合 | Boost | BSL |
iniparser 以極簡 API、零依賴、穩定成熟,成為嵌入式、系統工具、守護進程等 C 專案的配置管理首選。建議將上述範例整合至專案建置系統,建立統一的 ConfigManager 模組,封裝載入、存取、熱重載、驗證邏輯,提升維護效率。