0Pricing
C Academy · 课时

解析选项

处理标志

解析选项 是 CoddyKit 上的免费 C Academy 课时。 这是第 2 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 C Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 C Academy 课程共包含 4 节课。

选项与位置参数

命令行参数有两种形式。位置参数是文件名之类的值。选项(也称为标志)以短横线开头,例如 -v 或 --help。

本课将介绍如何手动检测和处理标志。

#include <stdio.h>

int main(int argc, char *argv[]) {
    for (int i = 1; i < argc; i++) {
        if (argv[i][0] == '-')
            printf("option: %s\n", argv[i]);
        else
            printf("value:  %s\n", argv[i]);
    }
    return 0;
}

检测标志

要检查某个特定标志,请使用 strcmp 将每个参数进行比较。

下面的示例在遇到 -v 时设置一个布尔值,以启用详细模式。

#include <stdio.h>
#include <string.h>

int main(int argc, char *argv[]) {
    int verbose = 0;
    for (int i = 1; i < argc; i++) {
        if (strcmp(argv[i], "-v") == 0)
            verbose = 1;
    }
    printf("verbose = %d\n", verbose);
    return 0;
}

支持长选项

许多工具同时接受短格式(-h)和长格式(--help)。

使用由 || 连接的两次比较,即可检查这两种写法。

#include <stdio.h>
#include <string.h>

int main(int argc, char *argv[]) {
    for (int i = 1; i < argc; i++) {
        if (strcmp(argv[i], "-h") == 0 ||
            strcmp(argv[i], "--help") == 0) {
            printf("Usage: prog [options]\n");
            return 0;
        }
    }
    printf("No help requested\n");
    return 0;
}

需要取值的选项

有些标志需要一个参数,例如 -o output.txt。遇到这类标志时,argv 中的下一个元素就是它的值。

请将循环索引前移,并检查是否已经越过末尾。

#include <stdio.h>
#include <string.h>

int main(int argc, char *argv[]) {
    const char *output = "default.txt";
    for (int i = 1; i < argc; i++) {
        if (strcmp(argv[i], "-o") == 0 && i + 1 < argc) {
            output = argv[++i];
        }
    }
    printf("Output file: %s\n", output);
    return 0;
}

处理缺少的值

如果 -o 是最后一个参数,那么它后面没有值。读取 argv[i+1] 会超出范围。

使用下一个标记之前,务必先测试 i + 1 < argc;否则应报告错误。

#include <stdio.h>
#include <string.h>

int main(int argc, char *argv[]) {
    for (int i = 1; i < argc; i++) {
        if (strcmp(argv[i], "-n") == 0) {
            if (i + 1 >= argc) {
                printf("Error: -n needs a value\n");
                return 1;
            }
            printf("n = %s\n", argv[++i]);
        }
    }
    return 0;
}

组合布尔标志和值

实际的解析器会同时跟踪多个标志:有些是布尔标志,有些带有值。请为每个设置分别使用变量。

#include <stdio.h>
#include <string.h>

int main(int argc, char *argv[]) {
    int verbose = 0;
    const char *name = "world";
    for (int i = 1; i < argc; i++) {
        if (strcmp(argv[i], "-v") == 0) verbose = 1;
        else if (strcmp(argv[i], "-name") == 0 && i+1 < argc) name = argv[++i];
    }
    if (verbose) printf("verbose mode\n");
    printf("Hello, %s\n", name);
    return 0;
}

识别选项结束位置

按照惯例,单独出现的 -- 表示选项结束。它后面的所有内容都会被视为位置参数,即使它们以短横线开头也是如此。

这样,用户就可以传入以 - 开头的文件名。

#include <stdio.h>
#include <string.h>

int main(int argc, char *argv[]) {
    int opts_done = 0;
    for (int i = 1; i < argc; i++) {
        if (!opts_done && strcmp(argv[i], "--") == 0) {
            opts_done = 1;
            continue;
        }
        printf("%s: %s\n", opts_done ? "value" : "token", argv[i]);
    }
    return 0;
}

收集位置参数

很多时候,您既需要标志,也需要一个文件列表。跳过已识别的选项,并将其余内容保存为位置参数。

#include <stdio.h>
#include <string.h>

int main(int argc, char *argv[]) {
    for (int i = 1; i < argc; i++) {
        if (argv[i][0] == '-') continue;
        printf("file: %s\n", argv[i]);
    }
    return 0;
}

处理未知选项

友好的工具会报告未知标志,而不是默默忽略它们。请将参数与已知选项进行比较,否则就发出警告。

#include <stdio.h>
#include <string.h>

int main(int argc, char *argv[]) {
    for (int i = 1; i < argc; i++) {
        if (argv[i][0] != '-') continue;
        if (strcmp(argv[i], "-v") != 0)
            printf("Unknown option: %s\n", argv[i]);
    }
    return 0;
}

转换选项值

选项值会以字符串形式传入。请使用 strtol 转换数字值;该函数还会通过末尾指针报告解析错误。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(int argc, char *argv[]) {
    int count = 1;
    for (int i = 1; i < argc; i++) {
        if (strcmp(argv[i], "-c") == 0 && i+1 < argc)
            count = (int) strtol(argv[++i], NULL, 10);
    }
    printf("count = %d\n", count);
    return 0;
}

为什么需要真正的解析器

手动解析虽然可行,但遇到组合短标志(-vf)、= 语法(--name=foo)以及顺序规则时,代码会变得杂乱。

下一节将介绍标准的 getopt 函数,它可以替您处理这些约定。

#include <stdio.h>

int main(int argc, char *argv[]) {
    printf("Parsed %d tokens manually\n", argc - 1);
    return 0;
}

快速检查

测试您对选项解析常见陷阱的理解。

回顾

您已经学习了手动解析选项:

  • 标志以 - 开头;使用 strcmp 进行比较。
  • 使用 || 同时支持短格式和长格式。
  • 需要取值的选项会使用下一个标记——使用 i + 1 < argc 进行保护。
  • -- 表示选项解析结束;报告未知标志;使用 strtol 转换数字值。

常见问题解答

「解析选项」课时是免费的吗?

是的 — 「解析选项」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 C Academy 课程的其余内容,请升级到 CoddyKit PRO。 C Academy 课程共包含 4 节课。

「解析选项」这节课中我会学到什么?

处理标志 你通过在浏览器中直接运行的动手代码来练习 C Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

学习 C Academy 需要有经验吗?

无需任何先前经验。CoddyKit 上的 C Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 2 节课,共 4 节。

「解析选项」课时需要多长时间?

大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。

我能在这节 C Academy 课中编写并运行代码吗?

能。每节 C Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。

此课程中的所有课时

  1. argc 与 argv
  2. 解析选项
  3. getopt
  4. 构建 CLI 工具
← 返回 C Academy