且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

在 C 中解析命令行参数

更新时间:2023-08-25 23:04:28

据我所知,在 C 中解析命令行参数的三种最流行的方法是:

To my knowledge, the three most popular ways how to parse command line arguments in C are:

  • Getopt(#include 来自 POSIX C 库),可以解决简单的参数解析任务.如果您对 bash 有点熟悉,那么 bash 的内置 getopt 是基于 GNU libc 的 Getopt.
  • Argp(#include 来自 GNU C 库),它可以解决更复杂的任务并照顾的东西,例如:
    • -?, --help 用于帮助信息,包括电子邮件地址
    • -V, --version 用于版本信息
    • --usage 用于使用信息
    • Getopt (#include <unistd.h> from the POSIX C Library), which can solve simple argument parsing tasks. If you're a bit familiar with bash, the getopt built-in of bash is based on Getopt from the GNU libc.
    • Argp (#include <argp.h> from the GNU C Library), which can solve more complex tasks and takes care of stuff like, for example:
      • -?, --help for help message, including email address
      • -V, --version for version information
      • --usage for usage message

      GNU C 库文档有一些很好的 Getopt 和 Argp 示例.

      The GNU C Library documentation has some nice examples for Getopt and Argp.

      #include <stdbool.h>
      #include <stdio.h>
      #include <stdlib.h>
      #include <unistd.h>
      
      int main(int argc, char *argv[])
      {
          bool isCaseInsensitive = false;
          int opt;
          enum { CHARACTER_MODE, WORD_MODE, LINE_MODE } mode = CHARACTER_MODE;
      
          while ((opt = getopt(argc, argv, "ilw")) != -1) {
              switch (opt) {
              case 'i': isCaseInsensitive = true; break;
              case 'l': mode = LINE_MODE; break;
              case 'w': mode = WORD_MODE; break;
              default:
                  fprintf(stderr, "Usage: %s [-ilw] [file...]
      ", argv[0]);
                  exit(EXIT_FAILURE);
              }
          }
      
          // Now optind (declared extern int by <unistd.h>) is the index of the first non-option argument.
          // If it is >= argc, there were no non-option arguments.
      
          // ...
      }
      

      使用Argp的示例

      #include <argp.h>
      #include <stdbool.h>
      
      const char *argp_program_version = "programname programversion";
      const char *argp_program_bug_address = "<your@email.address>";
      static char doc[] = "Your program description.";
      static char args_doc[] = "[FILENAME]...";
      static struct argp_option options[] = { 
          { "line", 'l', 0, 0, "Compare lines instead of characters."},
          { "word", 'w', 0, 0, "Compare words instead of characters."},
          { "nocase", 'i', 0, 0, "Compare case insensitive instead of case sensitive."},
          { 0 } 
      };
      
      struct arguments {
          enum { CHARACTER_MODE, WORD_MODE, LINE_MODE } mode;
          bool isCaseInsensitive;
      };
      
      static error_t parse_opt(int key, char *arg, struct argp_state *state) {
          struct arguments *arguments = state->input;
          switch (key) {
          case 'l': arguments->mode = LINE_MODE; break;
          case 'w': arguments->mode = WORD_MODE; break;
          case 'i': arguments->isCaseInsensitive = true; break;
          case ARGP_KEY_ARG: return 0;
          default: return ARGP_ERR_UNKNOWN;
          }   
          return 0;
      }
      
      static struct argp argp = { options, parse_opt, args_doc, doc, 0, 0, 0 };
      
      int main(int argc, char *argv[])
      {
          struct arguments arguments;
      
          arguments.mode = CHARACTER_MODE;
          arguments.isCaseInsensitive = false;
      
          argp_parse(&argp, argc, argv, 0, 0, &arguments);
      
          // ...
      }
      

      自己动手的示例

      #include <stdbool.h>
      #include <stdio.h>
      #include <stdlib.h>
      
      int main(int argc, char *argv[])
      {   
          bool isCaseInsensitive = false;
          enum { CHARACTER_MODE, WORD_MODE, LINE_MODE } mode = CHARACTER_MODE;
          size_t optind;
          for (optind = 1; optind < argc && argv[optind][0] == '-'; optind++) {
              switch (argv[optind][1]) {
              case 'i': isCaseInsensitive = true; break;
              case 'l': mode = LINE_MODE; break;
              case 'w': mode = WORD_MODE; break;
              default:
                  fprintf(stderr, "Usage: %s [-ilw] [file...]
      ", argv[0]);
                  exit(EXIT_FAILURE);
              }   
          }
          argv += optind;
      
          // *argv points to the remaining non-option arguments.
          // If *argv is NULL, there were no non-option arguments.
      
          // ...
      }   
      

      免责声明:我是 Argp 的新手,该示例可能包含错误.

      Disclaimer: I am new to Argp, the example might contain errors.