大家好,欢迎来到IT知识分享网。
argp
是一个在 GNU C Library (glibc) 中的库,用于解析命令行参数。它为 UNIX 风格的命令行参数提供了一种简洁和统一的方法。
以下是一个简单的使用 argp
解析命令行参数的例子:
- 先确保您的系统中有
argp
。它通常随glibc
一起分发,所以大多数 Linux 系统上应该都有。 - 下面我们来看一个实例。
// 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
函数的参数:
- int key:
- 这个参数表示当前正在处理的命令行参数的标识符或键。
- 对于短选项(例如
-v
),它是字符的 ASCII 值(在这种情况下,'v'
)。 - 对于长选项(例如
--verbose
),它是在argp_option
结构体中为这个选项指定的值。 - 还有一些预定义的键值(例如
ARGP_KEY_ARG
或ARGP_KEY_END
),它们表示特定的解析事件而不是特定的选项。
- char *arg:
- 当当前处理的命令行参数带有关联值时(例如
-o output.txt
或--output=output.txt
),arg
指向这个关联值(在这个例子中是"output.txt"
)。 - 如果当前处理的参数没有关联值,
arg
将为NULL
。
- 当当前处理的命令行参数带有关联值时(例如
- 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
输出以下内容:
- 如果设置了,那么程序的用法语法。
- 由
ARGP_HELP_STD_USAGE
、ARGP_HELP_SEE
和ARGP_HELP_LONG
这三个标志决定的标准帮助消息。 - 如果设置了,那么
argp
结构中的args_doc
和doc
字段。
此外,你可以通过 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_num
和 argc
之间的区别:
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_num
为 0
,因此不会调用 argp_usage(state)
。但是,当我们解析到第二个非选项参数时,state->arg_num
将为 1
,我们会调用 argp_usage(state)
,因为这表示用户提供了多余的参数。
总之,当你希望确保只有一个非选项参数时,检查 state->arg_num >= 1
是正确的。
免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://yundeesoft.com/123256.html