標準 C 庫 `getopt`/`getopt_long` 僅在 POSIX 系統可用。Windows 下需自行實現或移植。本文提供一個輕量級 `wingetopt.h/cpp`,API 與 Linux 一致。
#include "wingetopt.h"
int main(int argc, char **argv) {
int c;
bool binary = false;
char *input = NULL, *output = NULL;
while ((c = getopt(argc, argv, "bhi:o:")) != -1) {
switch (c) {
case 'b': binary = true; break;
case 'i': input = optarg; break;
case 'o': output = optarg; break;
case 'h': default: usage(); return 1;
}
}
// ...
}
選項字符串 `"bhi:o:"` 中,冒號表示該選項需參數(`optarg` 指向參數)。
char *optarg = NULL;
int optind = 1, opterr = 1, optopt = 0;
int getopt(int argc, char **argv, const char *opts) {
static char *sp = NULL; // 當前掃描位置
if (sp == NULL || *sp == '\0') {
if (optind >= argc || argv[optind][0] != '-' || argv[optind][1] == '\0')
return -1;
if (strcmp(argv[optind], "--") == 0) { optind++; return -1; }
sp = argv[optind] + 1;
optind++;
}
char c = *sp++;
const char *cp = strchr(opts, c);
if (c == ':' || cp == NULL) { // 非法選項
if (opterr) fprintf(stderr, "illegal option -- %c\n", c);
return '?';
}
if (cp[1] == ':') { // 需參數
if (*sp != '\0') { optarg = sp; sp = NULL; }
else if (optind < argc) { optarg = argv[optind++]; }
else { if (opterr) fprintf(stderr, "option requires argument -- %c\n", c); return '?'; }
}
return c;
}
將 `wingetopt.h/.c` 加入項目,或編譯為靜態庫鏈接。支持 `getopt_long` 需更複雜實現(可參考 GNU getopt 源碼移植)。
移植 `getopt` 讓 Windows 命令行工具擁有統一的參數解析體驗。代碼輕量、無依賴、行為兼容 POSIX,是跨平台 C 程序的基礎設施。