Parsing command-line arguments in C?

后端 未结 12 798
眼角桃花
眼角桃花 2020-11-22 16:23

I\'m trying to write a program that can compare two files line by line, word by word, or character by character in C. It has to be able to read in command line options

12条回答
  •  不知归路
    2020-11-22 16:54

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

    • Getopt (#include 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 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
    • Doing it yourself, which I don't recommend for programs that would be given to somebody else, as there is too much that could go wrong or lower quality. The popular mistake of forgetting about '--' to stop option parsing is just one example.

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

    • http://www.gnu.org/software/libc/manual/html_node/Getopt.html
    • http://www.gnu.org/software/libc/manual/html_node/Argp.html

    Example for using Getopt

    #include 
    #include 
    #include 
    #include 
    
    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...]\n", argv[0]);
                exit(EXIT_FAILURE);
            }
        }
    
        // Now optind (declared extern int by ) is the index of the first non-option argument.
        // If it is >= argc, there were no non-option arguments.
    
        // ...
    }
    

    Example for using Argp

    #include 
    #include 
    
    const char *argp_program_version = "programname programversion";
    const char *argp_program_bug_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);
    
        // ...
    }
    

    Example for Doing it Yourself

    #include 
    #include 
    #include 
    
    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...]\n", argv[0]);
                exit(EXIT_FAILURE);
            }   
        }   
    
        // *argv points to the remaining non-option arguments.
        // If *argv is NULL, there were no non-option arguments.
    
        // ...
    }   
    

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

提交回复
热议问题