Linux C编程基础知识(命令行参数)

张开发
2026/4/7 5:31:54 15 分钟阅读

分享文章

Linux C编程基础知识(命令行参数)
getopt接口int getopt(int argc, char *const argv[], const char *optstring);参数说明参数作用argc/argv直接传入 main 函数的命令行参数个数 数组optstring选项规则字符串核心规则- 单个字符如 h→ 无参数选项-h- 字符 :如 p:→ 必须带参数的选项-p 8080- 字符 ::GNU 扩展→ 可选参数的选项-p8080不能有空格。关键全局变量getopt 内置变量作用optarg指向当前选项的参数值如 -p 8080optarg 8080optind下一个待解析的 argv索引解析完选项后可通过它获取非选项参数opterr非 0 时getopt 自动输出错误提示如未知选项设为 0 可关闭自定义错误optopt存储无法识别的选项字符用于自定义错误提示。示例#include stdio.h #include unistd.h // getopt #include stdlib.h // atoi #include errno.h // errno #include limits.h // INT_MAX/INT_MIN #define VERSION v1.0.0 // 打印帮助信息 void print_help(const char *prog_name) { printf(用法%s [选项] [非选项参数]\n, prog_name); printf(选项\n); printf( -h 显示帮助信息\n); printf( -p 端口 指定服务端口1-65535必填\n); printf( -v 输出版本信息\n); } int main(int argc, char *argv[]) { int port 0; int opt; // 关闭getopt默认错误提示自定义更友好的错误 opterr 0; // 循环解析选项optstring hp:vh无参p有参v无参 while ((opt getopt(argc, argv, hp:v)) ! -1) { switch (opt) { case h: // 帮助 print_help(argv[0]); return 0; case p: // 端口带参数 // 安全转换端口替代atoi检测非法输入 errno 0; long temp strtol(optarg, NULL, 10); if (errno ! 0 || temp 1 || temp 65535 || temp INT_MAX) { fprintf(stderr, 错误端口必须是1-65535的整数输入%s\n, optarg); return 1; } port (int)temp; break; case v: // 版本 printf(版本%s\n, VERSION); return 0; case ?: // 未知选项/缺少参数 if (optopt p) { fprintf(stderr, 错误选项 -%c 需要传入端口参数\n, optopt); } else { fprintf(stderr, 错误未知选项 -%c\n, optopt); } fprintf(stderr, 使用 %s -h 查看帮助\n, argv[0]); return 1; default: return 1; } } // 检查必填参数 if (port 0) { fprintf(stderr, 错误必须通过 -p 指定端口\n); fprintf(stderr, 使用 %s -h 查看帮助\n, argv[0]); return 1; } // 解析非选项参数optind 指向第一个非选项参数 if (optind argc) { printf(\n非选项参数\n); for (int i optind; i argc; i) { printf( %s\n, argv[i]); } } // 业务逻辑 printf(\n程序启动端口 %d\n, port); return 0; }getopt_long接口int getopt_long(int argc, char *const argv[],const char *optstring,const struct option *longopts,int *longindex);参数说明参数作用argc/argv直接传入 main 函数的命令行参数个数 数组optstring短选项规则字符串和 getopt 完全一致如 hp:vlongopts长选项规则结构体数组核心定义每个长选项的名称、参数要求等longindex输出参数存储当前解析到的长选项在 longopts 中的索引传 NULL 则忽略长选项核心结构体struct option这是 getopt_long 的关键每个元素对应一个长选项struct option { const char *name; // 长选项名如 help、port int has_arg; // 参数要求 // no_argument (0) → 无参数如 --help // required_argument (1) → 必须带参数如 --port // optional_argument (2) → 可选参数如 --logdebug int *flag; // 标志位 // NULL → getopt_long 返回 val 的值 // 非NULL → 将 val 赋值给 *flag函数返回 0 int val; // 映射值 // 通常设为对应的短选项字符如 h、p实现长短选项联动 };⚠️ 注意结构体数组必须以全 0 元素结尾{0, 0, 0, 0}否则会导致内存越界。全局变量和 getopt 通用变量作用optarg指向当前选项的参数值长短选项通用如 --port 8080 → optarg8080optind下一个待解析的 argv 索引解析完选项后获取非选项参数opterr非 0 时自动输出错误提示设为 0 可自定义错误optopt存储出错的短选项字符长选项出错时 optopt0示例#include stdio.h #include unistd.h #include getopt.h #include stdlib.h #include errno.h #include limits.h #define VERSION v2.0.0 // 打印帮助信息 void print_help(const char *prog_name) { printf(用法%s [选项] [非选项参数]\n, prog_name); printf(选项说明\n); printf( -h, --help 显示帮助信息并退出\n); printf( -p, --port 端口 指定服务端口1-65535必填\n); printf( -v, --version 输出版本信息并退出\n); printf( -d, --debug 启用调试模式\n); } int main(int argc, char *argv[]) { int port 0; int debug_mode 0; int opt; // 存储解析返回值短选项字符/0/-1 int longindex 0; // 存储长选项索引可选 // 定义长选项结构体数组核心 static struct option long_options[] { {help, no_argument, 0, h}, // --help → 返回 h {port, required_argument, 0, p}, // --port → 返回 p {version, no_argument, 0, v}, // --version → 返回 v {debug, no_argument, 0, d}, // --debug → 返回 d {0, 0, 0, 0 } // 结束标志必须 }; // 关闭默认错误提示自定义更友好的错误 opterr 0; // 循环解析长短选项optstring 仍为短选项规则 while ((opt getopt_long(argc, argv, hp:vd, long_options, longindex)) ! -1) { switch (opt) { case h: // 帮助-h/--help print_help(argv[0]); return 0; case p: // 端口-p/--port // 安全转换端口避免atoi的缺陷 errno 0; long temp_port strtol(optarg, NULL, 10); if (errno ! 0 || temp_port 1 || temp_port 65535 || temp_port INT_MAX) { fprintf(stderr, 错误端口必须是1-65535的整数输入%s\n, optarg); return 1; } port (int)temp_port; break; case v: // 版本-v/--version printf(程序版本%s\n, VERSION); return 0; case d: // 调试-d/--debug debug_mode 1; printf(✅ 调试模式已启用\n); break; case 0: // flag非NULL时返回0本例未用到仅演示 printf(长选项 %s 触发无短选项映射\n, long_options[longindex].name); break; case ?: // 错误未知选项/缺少参数 if (optopt ! 0) { // 短选项错误如 -x、-p无参数 if (optopt p) { fprintf(stderr, 错误选项 -%c/--port 需要传入端口参数\n, optopt); } else { fprintf(stderr, 错误未知短选项 -%c\n, optopt); } } else { // 长选项错误如 --xxx fprintf(stderr, 错误未知长选项 %s\n, argv[optind-1]); } fprintf(stderr, 使用 %s --help 查看帮助\n, argv[0]); return 1; default: return 1; } } // 检查必填参数 if (port 0) { fprintf(stderr, 错误必须通过 -p/--port 指定端口\n); fprintf(stderr, 使用 %s --help 查看帮助\n, argv[0]); return 1; } // 解析非选项参数optind 指向第一个非选项参数 if (optind argc) { printf(\n 非选项参数待处理\n); for (int i optind; i argc; i) { printf( - %s\n, argv[i]); } } // 业务逻辑输出 printf(\n 服务启动配置\n); printf( 端口%d\n, port); printf( 调试模式%s\n, debug_mode ? 开启 : 关闭); return 0; }

更多文章