argp包处理命令行参数

argp包处理命令行参数argp 是一个在 GNUCLibrary glibc 中的库 用于解析命令行参数

大家好,欢迎来到IT知识分享网。

argp 是一个在 GNU C Library (glibc) 中的库,用于解析命令行参数。它为 UNIX 风格的命令行参数提供了一种简洁和统一的方法。

以下是一个简单的使用 argp 解析命令行参数的例子:

  1. 先确保您的系统中有 argp。它通常随 glibc 一起分发,所以大多数 Linux 系统上应该都有。
  2. 下面我们来看一个实例。
// test.c #include <stdio.h> #include <stdlib.h> #include <string.h> #include <argp.h> struct arguments { 
    int compile_only; int generate_assembly; int output; char *output_file; int verbose; char *input_file; }; char cmd[1024]; char filename[] = "./a.c"; static char doc[] = "Welcome to Argp"; static struct argp_option options[] = { 
    { 
   "compile", 'c', 0, 0, "Compile Only"}, { 
   "assembly", 's', 0, 0, "Generate Assembly Only"}, { 
   "output", 'o', "FILE", 0, "Output To FILE"}, { 
   "verbose", 'v', 0, 0, "Verbose mode"}, { 
   0}}; static error_t parse_opt(int key, char *arg, struct argp_state *state) { 
    struct arguments *arguments = state->input; switch (key) { 
    case 'c': arguments->compile_only = 1; break; case 's': arguments->generate_assembly = 1; break; case 'o': arguments->output = 1; arguments->output_file = arg; break; case 'v': arguments->verbose = 1; break; case ARGP_KEY_ARG: if (!arguments->input_file) { 
    arguments->input_file = arg; printf("arg = %s\n", arg); } else { 
    argp_usage(state); } break; default: return ARGP_ERR_UNKNOWN; } return 0; } static void verbose_on(int v, char *s) { 
    if (v) { 
    puts(s); } } static struct argp argp = { 
   options, parse_opt, "FILE", doc}; int main(int argc, char *argv[]) { 
    struct arguments arguments; arguments.compile_only = 0; arguments.output = 0; arguments.generate_assembly = 1; arguments.output_file = "output"; // 默认值 arguments.verbose = 0; arguments.input_file = NULL; // 默认值 argp_parse(&argp, argc, argv, 0, 0, &arguments); if (arguments.compile_only) { 
    sprintf(cmd, "gcc %s -o ./a.o", filename); verbose_on(arguments.verbose, cmd); if (system(cmd) != 0) { 
    fprintf(stderr, "Assembly failed.\n"); return 1; } } if (arguments.generate_assembly) { 
    sprintf(cmd, "gcc -S %s -o a.s", filename); verbose_on(arguments.verbose, cmd); if (system(cmd) != 0) { 
    fprintf(stderr, "Assembly failed.\n"); return 1; } } if (arguments.output) { 
    sprintf(cmd, "gcc %s -o %s", filename, arguments.output_file); verbose_on(arguments.verbose, cmd); if (system(cmd) != 0) { 
    fprintf(stderr, "Linking failed.\n"); return 1; } } return 0; } // ./test a.c 默认 生成a.s // ./test -c a.c 生成a.o // ./test -s a.c 汇编 生成a.s // ./test -v -c a.c 生成a.o 同时输出编译过程 // ./test -v -s a.c 汇编 生成a.s 同时输出编译过程 // ./test --help 输出全部编译选项信息 

parse_opt

当使用 argp 库进行命令行参数解析时,需要定义一个函数来处理每一个命令行参数。这个函数通常命名为 parse_opt,但实际上可以命名为任何想要的名字。这个函数的签名必须匹配 argp 期望的格式,即接受三个参数,并返回一个 error_t 类型的值。

static error_t parse_opt(int key, char *arg, struct argp_state *state); 

这里,我们来深入探究 parse_opt 函数的参数:

  1. int key:
    • 这个参数表示当前正在处理的命令行参数的标识符或键。
    • 对于短选项(例如 -v),它是字符的 ASCII 值(在这种情况下,'v')。
    • 对于长选项(例如 --verbose),它是在 argp_option 结构体中为这个选项指定的值。
    • 还有一些预定义的键值(例如 ARGP_KEY_ARGARGP_KEY_END),它们表示特定的解析事件而不是特定的选项。
  2. char *arg:
    • 当当前处理的命令行参数带有关联值时(例如 -o output.txt--output=output.txt),arg 指向这个关联值(在这个例子中是 "output.txt")。
    • 如果当前处理的参数没有关联值,arg 将为 NULL
  3. struct argp_state *state:
    • 这是一个指向当前解析状态的指针,其类型为 struct argp_state
    • 通过这个结构体,可以访问有关当前解析状态的多种信息,例如:还有多少参数未解析、当前解析的是哪个参数、在调用 argp_parse 时传入的输入数据等。
    • 常见的用途是通过 state->input 来获取一个指向存储解析结果的结构体的指针,但还有许多其他字段和用途。

parse_opt 函数内部,通常会使用一个 switch 语句来检查 key 参数,并据此决定如何处理当前的命令行参数。如果发现任何错误(例如一个参数没有预期的关联值,或者提供了不支持的参数),可以返回一个错误代码。如果一切正常,可以简单地返回 0(代表成功)。


argp_usage

argp_usage 是 C 语言的 argp 库函数,用于输出关于如何使用程序的信息,然后退出程序。这通常在用户提供了某些无效的命令行参数时被调用,以通知用户正确的使用方法。

argp_usage(state); 

参数:

  • state: 指向一个 argp_state 结构的指针,该结构包含了 argp 的解析状态。这通常是在 argp 的解析函数中被传入的。

用法:

当你检测到用户的输入是非法的或者不完整的,你可以调用 argp_usage 来显示帮助信息。例如,如果你的程序需要至少一个命令行参数,但用户没有提供任何参数,你可以这样使用它:

if (state->argc == 1) { 
    argp_usage(state); } 

输出内容:

默认情况下,argp_usage 输出以下内容:

  1. 如果设置了,那么程序的用法语法。
  2. ARGP_HELP_STD_USAGEARGP_HELP_SEEARGP_HELP_LONG 这三个标志决定的标准帮助消息。
  3. 如果设置了,那么 argp 结构中的 args_docdoc 字段。

此外,你可以通过 state 结构中的 flags 成员进一步定制输出。

示例:

考虑一个简单的 argp 例子,其中 argp_usage 用于确保至少有一个命令行参数:

const char *argp_program_version = "program 1.0"; const char *argp_program_bug_address = "<email@example.com>"; static char doc[] = "A simple program using argp"; static char args_doc[] = "ARG1 [STRING...]"; static error_t parse_opt(int key, char *arg, struct argp_state *state) { 
    switch (key) { 
    case ARGP_KEY_ARG: // 添加参数处理 break; case ARGP_KEY_END: if (state->arg_num < 1) { 
    // 如果没有足够的参数 argp_usage(state); } break; default: return ARGP_ERR_UNKNOWN; } return 0; } static struct argp_option options[] = { 
    { 
   0} }; static struct argp argp = { 
    options, parse_opt, args_doc, doc }; int main(int argc, char **argv) { 
    argp_parse(&argp, argc, argv, 0, 0, 0); return 0; } 

在上面的例子中,如果没有提供至少一个命令行参数,argp_usage 将被调用,并显示一个标准的用法消息。


有一个重要的细节。当使用 argp 解析命令行参数时,state->argc 包含了程序的名称及其参数。因此,如果用户只输入了程序的名字而没有提供任何其他参数,state->argc 就会是 1。

例如,考虑命令行调用:

./my_program 

在这种情况下,state->argc 将会是 1,因为只有一个字符串(即程序的名称)在参数列表中。

另一方面,如果用户调用程序并提供了一个参数:

./my_program some_arg 

那么 state->argc 将会是 2,因为参数列表中有两个字符串:程序的名称和 some_arg

因此,检查 state->argc == 1 是为了确定用户是否只提供了程序的名称而没有任何其他参数。


arg_numargc 之间的区别:

  • state->argc 表示命令行上提供的所有字符串的总数(包括程序名)。
  • state->arg_num 是已经解析的非选项参数的数量。这不包括程序名或任何前导选项。

所以,当我们检查 state->arg_num 时,我们只是查看非选项参数的数量。

如果你希望程序接受一个且仅一个非选项参数(例如输入文件名),那么当 state->arg_num >= 1 时,我们确实已经得到了一个参数。但如果用户提供了更多的非选项参数,我们应该在下一次解析中捕获它们,并可能决定调用 argp_usage(state)

ARGP_KEY_ARG 事件下,每次解析到一个非选项参数,state->arg_num 会增加。这意味着,在 ARGP_KEY_ARG 下,state->arg_num 的值从 0 开始,并在每次解析到一个新的非选项参数时增加。

因此,考虑以下逻辑:

switch (key) { 
    case ARGP_KEY_ARG: if (state->arg_num >= 1) { 
    argp_usage(state); } break; // ... 其他代码 ... } 

在这里,当我们解析到第一个非选项参数时(例如输入文件名),state->arg_num0,因此不会调用 argp_usage(state)。但是,当我们解析到第二个非选项参数时,state->arg_num 将为 1,我们会调用 argp_usage(state),因为这表示用户提供了多余的参数。

总之,当你希望确保只有一个非选项参数时,检查 state->arg_num >= 1 是正确的。

免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://yundeesoft.com/123256.html

(0)
上一篇 2024-11-19 12:45
下一篇 2024-11-19 13:00

相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注微信