標準 main(int argc, char **argv) 是程序與外界交互的契約。手寫參數解析易漏邊界、難擴展、錯誤提示差。本文提供一個**結構體驅動、表格化配置、支持必選/可選/默認值/前綴識別**的通用解析模板,開箱即用,工程級健壯。
-s value、長選項 (擴展)、組合選項 (擴展)。-h/-?/-H)。para_list[i].content。#define MAX_PARA 6
struct parameter {
int ID; // 參數編號
int content_num; // 該參數後跟隨的選項個數
bool IShave_prefix; // 是否有前綴 (如 -s)
char prefix[32]; // 前綴字符串
char content[256]; // 解析出的選項內容 (拼接)
bool IShave_default_c; // 是否有默認值
char default_content[256]; // 默認值
bool ISnot_optional; // 是否必選
bool ISinput; // 是否已被用戶輸入
};
// 參數表:集中聲明所有支持的選項
struct parameter para_list[MAX_PARA] = {
{1, 1, true, "-s", "", false, "", true, false}, // -s 必選
{2, 1, true, "-c", "", false, "", true, false}, // -c 必選
{3, 1, true, "-k", "", false, "", true, false}, // -k 必選
{4, 1, true, "-t", "", true, "NORMAL", false, false}, // -t 可選,默認 NORMAL
{5, 1, true, "-m", "", false, "", false, false}, // -m 可選
{6, 1, true, "-p", "", false, "", false, false} // -p 可選
};
generate_parameterint generate_parameter(int argc, char **argv) {
// 1. 無參數或求助
if (argc == 1 ||
(argc == 2 && (strcmp(argv[1], "-h")==0 || strcmp(argv[1], "-H")==0 || strcmp(argv[1], "-?")==0))) {
printf("Usage: ...\n"); // 此處可自動生成幫助
return 0; // 或視為錯誤返回 -1
}
// 2. 逐參數掃描
for (int i = 1; i < argc; i++) {
bool matched = false;
for (int j = 0; j < MAX_PARA; j++) {
if (strcmp(argv[i], para_list[j].prefix) == 0) {
matched = true;
// 重複檢查
if (para_list[j].ISinput) {
printf("The \"%s\" Can only input once.\n", para_list[j].prefix);
return -1;
}
// 選項數足夠性檢查
if (para_list[j].content_num >= argc - i) {
printf("The \"%s\" incomplete.\n", para_list[j].prefix);
return -1;
}
// 提取選項內容 (支持多選項拼接)
para_list[j].content[0] = '\0';
for (int k = 0; k < para_list[j].content_num; k++) {
sprintf(para_list[j].content, "%s%s", para_list[j].content, argv[i + 1 + k]);
}
i += para_list[j].content_num; // 跳過已消耗的選項
para_list[j].ISinput = true;
break;
}
}
if (!matched) {
printf("The \"%s\" is error!\n", argv[i]);
return -1;
}
}
// 3. 必選參數完整性檢查
for (int i = 0; i < MAX_PARA; i++) {
if (para_list[i].ISnot_optional && !para_list[i].ISinput) {
printf("The \"%s\" must be input.\n", para_list[i].prefix);
return -1;
}
}
return 0;
}
int main(int argc, char **argv) {
if (generate_parameter(argc, argv) != 0) return -1;
// 業務代碼直接使用解析結果
// para_list[0].content → -s 參數值
// para_list[3].content → -t 參數值 (若未輸入則為空,需自行填充默認值邏輯)
// 示例:應用默認值
for (int i = 0; i < MAX_PARA; i++) {
if (para_list[i].IShave_default_c && !para_list[i].ISinput) {
strcpy(para_list[i].content, para_list[i].default_content);
}
}
// 你的核心邏輯從這裡開始...
return 0;
}
--server=addr 格式,strncmp(argv[i], "--", 2) 分支處理。type 字段 (INT/STRING/FLOAT),解析時 strtol/strtod 驗證並轉換存入 union。para_list 打印 prefix、ISnot_optional、default_content。git commit -m 風格,頂層分發子解析器。argp (GNU)、getopt_long (POSIX)、cxxopts/CLI11 (C++),複雜項目建議直接用成熟庫。這個模板以**數據驅動解析邏輯**,將「參數定義」與「解析代碼」分離,新增參數只需修改結構體數組,業務代碼零侵入。適合中小型 CLI 工具、嵌入式固件升級程序、測試腳本快速構建。理解其原理,也能更好地使用成熟的參數解析庫。