[c] Parsing command-line arguments in C

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 -l, -w, -i or --...

  • if the option is -l, it compares the files line by line.
  • if the option is -w, it compares the files word by word.
  • if the option is --, it automatically assumes that the next argument is the first filename.
  • if the option is -i, it compares them in a case insensitive manner.
  • defaults to comparing the files character by character.

It's not supposed to matter how many times the options are input as long as -w and -l aren't inputted at the same time and there are no more or less than two files.

I don't even know where to begin with parsing the command line arguments.

So this is the code that I came up with for everything. I haven't error checked it quite yet, but am I writing things in an overcomplicated manner?

/*
 * Functions to compare files.
 */
int compare_line();
int compare_word();
int compare_char();
int case_insens();

/*
 * Program to compare the information in two files and print message saying
 * whether or not this was successful.
 */
int main(int argc, char* argv[])
{
    /* Loop counter */
    size_t i = 0;

    /* Variables for functions */
    int caseIns = 0;
    int line = 0;
    int word = 0;

    /* File pointers */
    FILE *fp1, *fp2;

    /*
     * Read through command-line arguments for options.
     */
    for (i = 1; i < argc; i++)
    {
        printf("argv[%u] = %s\n", i, argv[i]);
        if (argv[i][0] == '-')
        {
             if (argv[i][1] == 'i')
             {
                 caseIns = 1;
             }
             if (argv[i][1] == 'l')
             {
                 line = 1;
             }
             if (argv[i][1] == 'w')
             {
                 word = 1;
             }
             if (argv[i][1] == '-')
             {
                 fp1 = argv[i][2];
                 fp2 = argv[i][3];
             }
             else
             {
                 printf("Invalid option.");
                 return 2;
             }
        }
        else
        {
           fp1(argv[i]);
           fp2(argv[i][1]);
        }
    }

    /*
     * Check that files can be opened.
     */
    if(((fp1 = fopen(fp1, "rb")) ==  NULL) || ((fp2 = fopen(fp2, "rb")) == NULL))
    {
        perror("fopen()");
        return 3;
    }
    else
    {
        if (caseIns == 1)
        {
            if(line == 1 && word == 1)
            {
                printf("That is invalid.");
                return 2;
            }
            if(line == 1 && word == 0)
            {
                if(compare_line(case_insens(fp1, fp2)) == 0)
                        return 0;
            }
            if(line == 0 && word == 1)
            {
                if(compare_word(case_insens(fp1, fp2)) == 0)
                    return 0;
            }
            else
            {
                if(compare_char(case_insens(fp1,fp2)) == 0)
                    return 0;
            }
        }
        else
        {
            if(line == 1 && word == 1)
            {
                printf("That is invalid.");
                return 2;
            }
            if(line == 1 && word == 0)
            {
                if(compare_line(fp1, fp2) == 0)
                    return 0;
            }
            if(line == 0 && word == 1)
            {
                if(compare_word(fp1, fp2) == 0)
                    return 0;
            }
            else
            {
                if(compare_char(fp1, fp2) == 0)
                    return 0;
            }
        }
    }
    return 1;

    if(((fp1 = fclose(fp1)) == NULL) || (((fp2 = fclose(fp2)) == NULL)))
    {
        perror("fclose()");
        return 3;
    }
    else
    {
        fp1 = fclose(fp1);
        fp2 = fclose(fp2);
    }
}

/*
 * Function to compare two files line-by-line.
 */
int compare_line(FILE *fp1, FILE *fp2)
{
    /* Buffer variables to store the lines in the file */
    char buff1 [LINESIZE];
    char buff2 [LINESIZE];

    /* Check that neither is the end of file */
    while((!feof(fp1)) && (!feof(fp2)))
    {
        /* Go through files line by line */
        fgets(buff1, LINESIZE, fp1);
        fgets(buff2, LINESIZE, fp2);
    }

    /* Compare files line by line */
    if(strcmp(buff1, buff2) == 0)
    {
        printf("Files are equal.\n");
        return 0;
    }
    printf("Files are not equal.\n");
    return 1;
}

/*
 * Function to compare two files word-by-word.
 */
int compare_word(FILE *fp1, FILE *fp2)
{
    /* File pointers */
    FILE *fp1, *fp2;

    /* Arrays to store words */
    char fp1words[LINESIZE];
    char fp2words[LINESIZE];

    if(strtok(fp1, " ") == NULL || strtok(fp2, " ") == NULL)
    {
        printf("File is empty. Cannot compare.\n");
        return 0;
    }
    else
    {
        fp1words = strtok(fp1, " ");
        fp2words = strtok(fp2, " ");

        if(fp1words == fp2words)
        {
            fputs(fp1words);
            fputs(fp2words);
            printf("Files are equal.\n");
            return 0;
        }
    }
    return 1;
}

/*
 * Function to compare two files character by character.
 */
int compare_char(FILE *fp1,FILE *fp2)
{
    /* Variables to store the characters from both files */
    int c;
    int d;

    /* Buffer variables to store chars */
    char buff1 [LINESIZE];
    char buff2 [LINESIZE];

    while(((c = fgetc(fp1))!= EOF) && (((d = fgetc(fp2))!=EOF)))
    {
        if(c == d)
        {
            if((fscanf(fp1, "%c", buff1)) == (fscanf(fp2, "%c", buff2)))
            {
                printf("Files have equivalent characters.\n");
                return 1;
                break;
            }
        }

    }
    return 0;
}

/*
 * Function to compare two files in a case-insensitive manner.
 */
int case_insens(FILE *fp1, FILE *fp2, size_t n)
{
    /* Pointers for files. */
    FILE *fp1, *fp2;

    /* Variable to go through files. */
    size_t i = 0;

    /* Arrays to store file information. */
    char fp1store[LINESIZE];
    char fp2store[LINESIZE];

    while(!feof(fp1) && !feof(fp2))
    {
        for(i = 0; i < n; i++)
        {
            fscanf(fp1, "%s", fp1store);
            fscanf(fp2, "%s", fp2store);

            fp1store = tolower(fp1store);
            fp2store = tolower(fp2store);

            return 1;
        }
    }
    return 0;
}

This question is related to c command-line-arguments

The answer is



The suggestions for boost::program_options and GNU getopt are good ones.

However, for simple command line options I tend to use std::find

For example, to read the name of a file after a -f command line argument. You can also just detect if a single-word option has been passed in like -h for help.

#include <algorithm>

char* getCmdOption(char ** begin, char ** end, const std::string & option)
{
    char ** itr = std::find(begin, end, option);
    if (itr != end && ++itr != end)
    {
        return *itr;
    }
    return 0;
}

bool cmdOptionExists(char** begin, char** end, const std::string& option)
{
    return std::find(begin, end, option) != end;
}

int main(int argc, char * argv[])
{
    if(cmdOptionExists(argv, argv+argc, "-h"))
    {
        // Do stuff
    }

    char * filename = getCmdOption(argv, argv + argc, "-f");

    if (filename)
    {
        // Do interesting things
        // ...
    }

    return 0;
}

On thing to look out for with this approach you must use std::strings as the value for std::find otherwise the equality check is performed on the pointer values.


I hope it is okay to edit this response instead adding a new one, as this is based on the original answer. I re-wrote the functions slightly and encapsulated them in a class, so here is the code. I thought it might be practical to use it that way as well:

class InputParser{
    public:
        InputParser (int &argc, char **argv){
            for (int i=1; i < argc; ++i)
                this->tokens.push_back(std::string(argv[i]));
        }
        /// @author iain
        const std::string& getCmdOption(const std::string &option) const{
            std::vector<std::string>::const_iterator itr;
            itr =  std::find(this->tokens.begin(), this->tokens.end(), option);
            if (itr != this->tokens.end() && ++itr != this->tokens.end()){
                return *itr;
            }
            static const std::string empty_string("");
            return empty_string;
        }
        /// @author iain
        bool cmdOptionExists(const std::string &option) const{
            return std::find(this->tokens.begin(), this->tokens.end(), option)
                   != this->tokens.end();
        }
    private:
        std::vector <std::string> tokens;
};

int main(int argc, char **argv){
    InputParser input(argc, argv);
    if(input.cmdOptionExists("-h")){
        // Do stuff
    }
    const std::string &filename = input.getCmdOption("-f");
    if (!filename.empty()){
        // Do interesting things ...
    }
    return 0;
}

Your C/C++ program always has a main function. It looks like that:

    int main(int argc, char**argv) {
        ...
    }

Here argc is a number of command line arguments, that have been passed to your program, and argv is an array of strings with these arguments. So command line is separated in-to arguments by the caller process (this is not a single line, like in windows).

Now you need to sort them out:

  • Command name is always the first argument (index 0).
  • Options are just special arguments that specify how a program should work. By convention they start from - sign. Usually - for one letter options and -- for anything longer. So in your task "options" are all arguments, that start from - and are not the 0th.
  • Arguments. Just all other arguments which are not program name or options.

GNU GetOpt.

A simple example using GetOpt:

// C/C++ Libraries:
#include <string>
#include <iostream>
#include <unistd.h>

// Namespaces:
using namespace std;

int main(int argc, char** argv) {
    int opt;
    bool flagA = false;
    bool flagB = false;

    // Shut GetOpt error messages down (return '?'): 
    opterr = 0;

    // Retrieve the options:
    while ( (opt = getopt(argc, argv, "ab")) != -1 ) {  // for each option...
        switch ( opt ) {
            case 'a':
                    flagA = true;
                break;
            case 'b':
                    flagB = true;
                break;
            case '?':  // unknown option...
                    cerr << "Unknown option: '" << char(optopt) << "'!" << endl;
                break;
        }
    }

    // Debug:
    cout << "flagA = " << flagA << endl;
    cout << "flagB = " << flagB << endl;

    return 0;
}

You can also use optarg if you have options that accept arguments.


I'd recommend boost::program_options if you can use the Boost lib.

There's nothing specific in STL nor in the regular C++/C runtime libs.


I find it easier to use ezOptionParser. It's also a single header file, does not depend on anything but STL, works for Windows and Linux (very likely other platforms too), has no learning curve thanks to the examples, has features other libraries don't (like file import/export with comments, arbitrary option names with delimiters, auto usage formatting, etc), and is LGPL licensed.


argstream is quite similar to boost.program_option: it permits to bind variables to options, etc. However it does not handle options stored in a configuration file.


TCLAP is a really nice lightweight design and easy to use: http://tclap.sourceforge.net/


if this is linux/unix then the standard one to use is gnu getopt

http://www.gnu.org/s/libc/manual/html_node/Getopt.html



You can use GNU GetOpt (LGPL) or one of the various C++ ports, such as getoptpp (GPL).

A simple example using GetOpt of what you want (prog [-ab] input) is the following:

// C Libraries:
#include <string>
#include <iostream>
#include <unistd.h>

// Namespaces:
using namespace std;

int main(int argc, char** argv) {
    int opt;
    string input = "";
    bool flagA = false;
    bool flagB = false;

    // Retrieve the (non-option) argument:
    if ( (argc <= 1) || (argv[argc-1] == NULL) || (argv[argc-1][0] == '-') ) {  // there is NO input...
        cerr << "No argument provided!" << endl;
        //return 1;
    }
    else {  // there is an input...
        input = argv[argc-1];
    }

    // Debug:
    cout << "input = " << input << endl;

    // Shut GetOpt error messages down (return '?'): 
    opterr = 0;

    // Retrieve the options:
    while ( (opt = getopt(argc, argv, "ab")) != -1 ) {  // for each option...
        switch ( opt ) {
            case 'a':
                    flagA = true;
                break;
            case 'b':
                    flagB = true;
                break;
            case '?':  // unknown option...
                    cerr << "Unknown option: '" << char(optopt) << "'!" << endl;
                break;
        }
    }

    // Debug:
    cout << "flagA = " << flagA << endl;
    cout << "flagB = " << flagB << endl;

    return 0;
}

Instructional template for parsing command line arguments in C.

C:>programName -w -- fileOne.txt fileTwo.txt

BOOL argLine = FALSE;
BOOL argWord = FALSE;
BOOL argChar = FALSE;
char * fileName1 = NULL;
char * fileName2 = NULL;

int main(int argc, char * argv[]) {
    int i;
    printf("Argument count=%d\n",argc);
    for (i = 0; i < argc; i++) {
        printf("Argument %s\n",argv[i]);
        if (strcmp(argv[i],"-l")==0) {
            argLine = TRUE;
            printf("    argLine=TRUE\n");
        }
        else if (strcmp(argv[i],"-w")==0) {
            argWord = TRUE;
            printf("    argWord=TRUE\n");
        }
        else if (strcmp(argv[i],"-c")==0) {
            argChar = TRUE;
            printf("    argChar=TRUE\n");
        }
        else if (strcmp(argv[i],"--")==0) {
            if (i+1 <= argc) {
                fileName1 = argv[++i];
                printf("    fileName1=%s\n",fileName1);
            }
            if (i+1 <= argc) {
                fileName2 = argv[++i];
                printf("    fileName2=%s\n",fileName2);
            }
        }
    }
    return 0;
}

argstream is quite similar to boost.program_option: it permits to bind variables to options, etc. However it does not handle options stored in a configuration file.


If you just want to process command line options yourself, the easiest way is to put:

vector<string> args(argv + 1, argv + argc);

at the top of your main(). This copies all command-line arguments into a vector of std::strings. Then you can use == to compare strings easily, instead of endless strcmp() calls. For example:

int main(int argc, char **argv) {
    vector<string> args(argv + 1, argv + argc);
    string infname, outfname;

    // Loop over command-line args
    // (Actually I usually use an ordinary integer loop variable and compare
    // args[i] instead of *i -- don't tell anyone! ;)
    for (auto i = args.begin(); i != args.end(); ++i) {
        if (*i == "-h" || *i == "--help") {
            cout << "Syntax: foomatic -i <infile> -o <outfile>" << endl;
            return 0;
        } else if (*i == "-i") {
            infname = *++i;
        } else if (*i == "-o") {
            outfname = *++i;
        }
    }
}

[EDIT: I realised I was copying argv[0], the name of the program, into args -- fixed.]


You probably want to use an external library for that. There are many to chose from.

Boost has a very feature-rich (as usual) library Boost Program Options.

My personal favorite for the last few years has been TCLAP -- purely templated, hence no library or linking, automated '--help' generation and other goodies. See the simplest example from the docs.


I can suggest Templatized C++ Command Line Parser Library (some forks on GitHub are available), the API is very straightforward and (cited from the site):

the library is implemented entirely in header files making it easy to use and distribute with other software. It is licensed under the MIT License for worry free distribution.

This is an example from the manual, colored here for simplicity:

#include <string>
#include <iostream>
#include <algorithm>
#include <tclap/CmdLine.h>

int main(int argc, char** argv)
{

    // Wrap everything in a try block.  Do this every time,
    // because exceptions will be thrown for problems.
    try {

    // Define the command line object, and insert a message
    // that describes the program. The "Command description message"
    // is printed last in the help text. The second argument is the
    // delimiter (usually space) and the last one is the version number.
    // The CmdLine object parses the argv array based on the Arg objects
    // that it contains.
    TCLAP::CmdLine cmd("Command description message", ' ', "0.9");

    // Define a value argument and add it to the command line.
    // A value arg defines a flag and a type of value that it expects,
    // such as "-n Bishop".
    TCLAP::ValueArg<std::string> nameArg("n","name","Name to print",true,"homer","string");

    // Add the argument nameArg to the CmdLine object. The CmdLine object
    // uses this Arg to parse the command line.
    cmd.add( nameArg );

    // Define a switch and add it to the command line.
    // A switch arg is a boolean argument and only defines a flag that
    // indicates true or false.  In this example the SwitchArg adds itself
    // to the CmdLine object as part of the constructor.  This eliminates
    // the need to call the cmd.add() method.  All args have support in
    // their constructors to add themselves directly to the CmdLine object.
    // It doesn't matter which idiom you choose, they accomplish the same thing.
    TCLAP::SwitchArg reverseSwitch("r","reverse","Print name backwards", cmd, false);

    // Parse the argv array.
    cmd.parse( argc, argv );

    // Get the value parsed by each arg.
    std::string name = nameArg.getValue();
    bool reverseName = reverseSwitch.getValue();

    // Do what you intend.
    if ( reverseName )
    {
            std::reverse(name.begin(),name.end());
            std::cout << "My name (spelled backwards) is: " << name << std::endl;
    }
    else
            std::cout << "My name is: " << name << std::endl;


    } catch (TCLAP::ArgException &e)  // catch any exceptions
    { std::cerr << "error: " << e.error() << " for arg " << e.argId() << std::endl; }
}

With C++, the answer is usually in Boost...

Boost.Program Options


There are a number of good libraries available.

Boost Program Options is a fairly heavyweight solution, both because adding it to your project requires you to build boost, and the syntax is somewhat confusing (in my opinion). However, it can do pretty much everything including having the command line options override those set in configuration files.

SimpleOpt is a fairly comprehensive but simple command line processor. It is a single file and has a simple structure, but only handles the parsing of the command line into options, you have to do all of the type and range checking. It is good for both Windows and Unix and comes with a version of glob for Windows too.

getopt is available on Windows. It is the same as on Unix machines, but it is often a GPL library.


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

  • 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
  • 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.

Example for using Getopt

#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...]\n", 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.

    // ...
}

Example for using Argp

#include <argp.h>
#include <stdbool.h>

const char *argp_program_version = "programname programversion";
const char *argp_program_bug_address = "<[email protected]>";
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 <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...]\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.


There is a great general-purpose C library, libUCW, which includes neat command-line option parsing and configuration file loading.

The library also comes with good documentation and includes some other useful stuff (fast I/O, data structures, allocators, ...) but this can be used separately.

Example libUCW option parser (from the library docs)

#include <ucw/lib.h>
#include <ucw/opt.h>

int english;
int sugar;
int verbose;
char *tea_name;

static struct opt_section options = {
  OPT_ITEMS {
    OPT_HELP("A simple tea boiling console."),
    OPT_HELP("Usage: teapot [options] name-of-the-tea"),
    OPT_HELP(""),
    OPT_HELP("Options:"),
    OPT_HELP_OPTION,
    OPT_BOOL('e', "english-style", english, 0, "\tEnglish style (with milk)"),
    OPT_INT('s', "sugar", sugar, OPT_REQUIRED_VALUE, "<spoons>\tAmount of sugar (in teaspoons)"),
    OPT_INC('v', "verbose", verbose, 0, "\tVerbose (the more -v, the more verbose)"),
    OPT_STRING(OPT_POSITIONAL(1), NULL, tea_name, OPT_REQUIRED, ""),
    OPT_END
  }
};

int main(int argc, char **argv)
{
  opt_parse(&options, argv+1);
  return 0;
}

Tooting my own horn if I may, I'd also like to suggest taking a look at an option parsing library that I've written: dropt.

  • It's a C library (with a C++ wrapper if desired).
  • It's lightweight.
  • It's extensible (custom argument types can be easily added and have equal footing with built-in argument types).
  • It should be very portable (it's written in standard C) with no dependencies (other than the C standard library).
  • It has a very unrestrictive license (zlib/libpng).

One feature that it offers that many others don't is the ability to override earlier options. For example, if you have a shell alias:

alias bar="foo --flag1 --flag2 --flag3"

and you want to use bar but with--flag1 disabled, it allows you to do:

bar --flag1=0

Tooting my own horn if I may, I'd also like to suggest taking a look at an option parsing library that I've written: dropt.

  • It's a C library (with a C++ wrapper if desired).
  • It's lightweight.
  • It's extensible (custom argument types can be easily added and have equal footing with built-in argument types).
  • It should be very portable (it's written in standard C) with no dependencies (other than the C standard library).
  • It has a very unrestrictive license (zlib/libpng).

One feature that it offers that many others don't is the ability to override earlier options. For example, if you have a shell alias:

alias bar="foo --flag1 --flag2 --flag3"

and you want to use bar but with--flag1 disabled, it allows you to do:

bar --flag1=0

If you don't want to use boost, I'd recommend this little helper class.


I like C's getopt(), but then I'm old. :-)


I think that GNU GetOpt is not too immediate to use.

Qt and Boost could be a solution, but you need to download and compile a lot of code.

So I implemented a parser by myself that produces a std::map<std::string, std::string> of parameters.

For example, calling:

 ./myProgram -v -p 1234

map will be:

 ["-v"][""]
 ["-p"]["1234"]

Usage is:

int main(int argc, char *argv[]) {
    MainOptions mo(argc, argv);
    MainOptions::Option* opt = mo.getParamFromKey("-p");
    const string type = opt ? (*opt).second : "";
    cout << type << endl; /* Prints 1234 */
    /* Your check code */
}

MainOptions.h

#ifndef MAINOPTIONS_H_
#define MAINOPTIONS_H_

#include <map>
#include <string>

class MainOptions {
public:
    typedef std::pair<std::string, std::string> Option;
    MainOptions(int argc, char *argv[]);
    virtual ~MainOptions();
    std::string getAppName() const;
    bool hasKey(const std::string&) const;
    Option* getParamFromKey(const std::string&) const;
    void printOptions() const;
private:
    typedef std::map<std::string, std::string> Options;
    void parse();
    const char* const *begin() const;
    const char* const *end() const;
    const char* const *last() const;
    Options options_;
    int argc_;
    char** argv_;
    std::string appName_;
};

MainOptions.cpp

#include "MainOptions.h"

#include <iostream>

using namespace std;

MainOptions::MainOptions(int argc, char* argv[]) :
        argc_(argc),
        argv_(argv) {
    appName_ = argv_[0];
    this->parse();
}

MainOptions::~MainOptions() {
}

std::string MainOptions::getAppName() const {
    return appName_;
}

void MainOptions::parse() {
    typedef pair<string, string> Option;
    Option* option = new pair<string, string>();
    for (const char* const * i = this->begin() + 1; i != this->end(); i++) {
        const string p = *i;
        if (option->first == "" && p[0] == '-') {
            option->first = p;
            if (i == this->last()) {
                options_.insert(Option(option->first, option->second));
            }
            continue;
        } else if (option->first != "" && p[0] == '-') {
            option->second = "null"; /* or leave empty? */
            options_.insert(Option(option->first, option->second));
            option->first = p;
            option->second = "";
            if (i == this->last()) {
                options_.insert(Option(option->first, option->second));
            }
            continue;
        } else if (option->first != "") {
            option->second = p;
            options_.insert(Option(option->first, option->second));
            option->first = "";
            option->second = "";
            continue;
        }
    }
}

void MainOptions::printOptions() const {
    std::map<std::string, std::string>::const_iterator m = options_.begin();
    int i = 0;
    if (options_.empty()) {
        cout << "No parameters\n";
    }
    for (; m != options_.end(); m++, ++i) {
        cout << "Parameter [" << i << "] [" << (*m).first << " " << (*m).second
                << "]\n";
    }
}

const char* const *MainOptions::begin() const {
    return argv_;
}

const char* const *MainOptions::end() const {
    return argv_ + argc_;
}

const char* const *MainOptions::last() const {
    return argv_ + argc_ - 1;
}

bool MainOptions::hasKey(const std::string& key) const {
    return options_.find(key) != options_.end();
}

MainOptions::Option* MainOptions::getParamFromKey(
        const std::string& key) const {
    const Options::const_iterator i = options_.find(key);
    MainOptions::Option* o = 0;
    if (i != options_.end()) {
        o = new MainOptions::Option((*i).first, (*i).second);
    }
    return o;
}

Yet another alternative is The Lean Mean C++ Option Parser:

http://optionparser.sourceforge.net

It is a header-only library (just a single header file, in fact) and unlike all the other suggestions it is also freestanding, i.e. it has no dependencies whatsoever. In particular there's no dependency on the STL. It does not even use exceptions or anything else that requires library support. This means it can be linked with plain C or other languages without introducing "foreign" libraries.

Like boost::program_options its API offers convenient direct access to options, i.e. you can write code like this

if (options[HELP]) ... ;

and

int verbosity = options[VERBOSE].count();

Unlike boost::program_options however this is simply using an array indexed with a (user-provided) enum. This offers the convenience of an associative container without the weight.

It's well documented and has a company-friendly license (MIT).

TLMC++OP includes a nice formatter for usage messages that can do line-wrapping and column alignment which is useful if you're localizing your program, because it ensures that the output will look good even in languages that have longer messages. It also saves you the nuisance of manually formatting your usage for 80 columns.


You could use an already created library for this

http://www.boost.org/doc/libs/1_44_0/doc/html/program_options.html


GNU GetOpt.

A simple example using GetOpt:

// C/C++ Libraries:
#include <string>
#include <iostream>
#include <unistd.h>

// Namespaces:
using namespace std;

int main(int argc, char** argv) {
    int opt;
    bool flagA = false;
    bool flagB = false;

    // Shut GetOpt error messages down (return '?'): 
    opterr = 0;

    // Retrieve the options:
    while ( (opt = getopt(argc, argv, "ab")) != -1 ) {  // for each option...
        switch ( opt ) {
            case 'a':
                    flagA = true;
                break;
            case 'b':
                    flagB = true;
                break;
            case '?':  // unknown option...
                    cerr << "Unknown option: '" << char(optopt) << "'!" << endl;
                break;
        }
    }

    // Debug:
    cout << "flagA = " << flagA << endl;
    cout << "flagB = " << flagB << endl;

    return 0;
}

You can also use optarg if you have options that accept arguments.


I have used GetPot for some projects: http://getpot.sourceforge.net/

Main feature: everything is in a single header file, no build hassles. Just save it somewhere on your machine and "#include" it in your file holding main()

Hasn't be updated recently, but it is nicely documented, and works well.


I wrote a tiny library that parses arguments similar to POpt, which I had several issues with, called XOpt. It uses GNU-style argument parsing and has a very similar interface to POpt.

I use it from time to time with great success, and it works pretty much anywhere.


If you just want to process command line options yourself, the easiest way is to put:

vector<string> args(argv + 1, argv + argc);

at the top of your main(). This copies all command-line arguments into a vector of std::strings. Then you can use == to compare strings easily, instead of endless strcmp() calls. For example:

int main(int argc, char **argv) {
    vector<string> args(argv + 1, argv + argc);
    string infname, outfname;

    // Loop over command-line args
    // (Actually I usually use an ordinary integer loop variable and compare
    // args[i] instead of *i -- don't tell anyone! ;)
    for (auto i = args.begin(); i != args.end(); ++i) {
        if (*i == "-h" || *i == "--help") {
            cout << "Syntax: foomatic -i <infile> -o <outfile>" << endl;
            return 0;
        } else if (*i == "-i") {
            infname = *++i;
        } else if (*i == "-o") {
            outfname = *++i;
        }
    }
}

[EDIT: I realised I was copying argv[0], the name of the program, into args -- fixed.]



for (int i = 1; i < argc; i++) {

    if (strcmp(argv[i],"-i")==0) {
        filename = argv[i+1];
        printf("filename: %s",filename);
    } else if (strcmp(argv[i],"-c")==0) {
        convergence = atoi(argv[i + 1]);
        printf("\nconvergence: %d",convergence);
    } else if (strcmp(argv[i],"-a")==0) {
        accuracy = atoi(argv[i + 1]);
        printf("\naccuracy:%d",accuracy);
    } else if (strcmp(argv[i],"-t")==0) {
        targetBitRate = atof(argv[i + 1]);
        printf("\ntargetBitRate:%f",targetBitRate);
    } else if (strcmp(argv[i],"-f")==0) {
        frameRate = atoi(argv[i + 1]);
        printf("\nframeRate:%d",frameRate);
    }

}

And there's a Google library available.

Really, command-line parsing is "solved." Just pick one.


Try CLPP library. It's simple and flexible library for command line parameters parsing. Header-only and cross-platform. Uses ISO C++ and Boost C++ libraries only. IMHO it is easier than Boost.Program_options.

Library: http://sourceforge.net/projects/clp-parser/

26 October 2010 - new release 2.0rc. Many bugs fixed, full refactoring of the source code, documentation, examples and comments have been corrected.


Google's gflags


I am using getopt() under windows/mingw :

while ((c = getopt(myargc, myargv, "vp:d:rcx")) != -1) {
        switch (c) {
        case 'v': // print version
            printf("%s Version %s\n", myargv[0], VERSION);
            exit(0);
            break;
        case 'p': // change local port to listen to
            strncpy(g_portnum, optarg, 10);
            break;
...

You can use James Theiler's "opt" package.

And a flattering post with some examples of how it is so much simpler than other approaches is here:

Opt 3.19 review and upgrades


And there's a Google library available.

Really, command-line parsing is "solved." Just pick one.


There are these tools in the GNU C Library, which includes GetOpt.

If you are using Qt and like the GetOpt interface, froglogic has published a nice interface here.


Boost.Program_options should do the trick


Try CLPP library. It's simple and flexible library for command line parameters parsing. Header-only and cross-platform. Uses ISO C++ and Boost C++ libraries only. IMHO it is easier than Boost.Program_options.

Library: http://sourceforge.net/projects/clp-parser

26 October 2010 - new release 2.0rc. Many bugs fixed, full refactoring of the source code, documentation, examples and comments have been corrected.


You could try my little options header (166 loc so easily hackable) options.hpp. It is a single header implementation and should do what you ask. It also prints you the help page automatically.


Following from my comment and from rbaleksandar's answer, the arguments passed to any program in C are string values. You are provided the argument count (argc) which gives you the argument indexes zero-based beginning with the name of the program currently being run (which is always argv[0]). That leaves all arguments between 1 - argc as the user supplied arguments for your program. Each will be a string that is contained in the argument vector (which is a pointer to an array of strings you will seen written as char *argv[], or equivalently as a function parameter char **argv) Each of the strings argv[1] to argv[argc-1] are available to you, you simply need to test which argument is which.

That will allow you to separate, and make them available as the command (cmd), the options (opt) and finally the argument (arg) to your cmd.

Now it is worth noting, that the rules of your shell (bash, etc..) apply to the arguments passed to your program, word-splitting, pathname and variable expansion apply before your code gets the arguments. So you must consider whether single or more commongly double-quoting will be required around any of your arguments to prevent the normal shell splitting that would otherwise apply (e.g. ls -al my file.txt would results in 4 user-supplied arguments to your code, while ls -al "my file.txt" or ls -al my\ file.txt which would result in the 3 your were expecting.

Putting all that together, your short bit of parsing could be done something like what follows. (you are also free to do it however you like, using a switch instead of nested ifs, etc...)

#include <stdio.h>

int main (int argc, char **argv) {

    char *cmd = NULL,   /* here, since you are using the arguments  */
         *opt = NULL,   /* themselves, you can simply use a pointer */
         *arg = NULL;   /* or the argument itself without a copy    */

    /* looping using the acutal argument index & vector */
    for (int i = 1; i < argc; i++) {
        if (*argv[i] != '-') {      /* checking if the 1st char is - */
            if (!cmd)               /* cmd is currently NULL, and    */
                cmd = argv[i];      /* no '-' it's going to be cmd   */
            else                    /* otherwise, cmd has value, so  */
                arg = argv[i];       /* the value will be opt        */
        }
        else                /* here the value has a leading '-', so  */
            opt = argv[i];  /* it will be the option */
    }

    printf ("\n cmd : %s\n opt : %s\n arg : %s\n\n",
            cmd, opt, arg);

    return 0;
}

Example Use/Output

If you run the code, you will find it provides separation for the arguments and provides separate pointers to facilitate their use:

$ ./bin/parse_cmd ls -la ./cs3000

 cmd : ls
 opt : -la
 arg : ./cs3000

(it is important to note, that if you were tasked with building a command string where you would need to copy multiple value to say opt or arg, then you could no longer simply use a pointer and would need to create storage, either though a simple declaring of arrays instead of pointer to begin with, or you could dynamically allocate storage as required with, e.g. malloc, calloc and/or realloc. Then you would have storage available to copy and concatenate values within.)

If this was your challenge, then between all the answer here, you should have a handle of how to approach your problem. If you must go further and actually have your program execute the cmd with the opt and the arg, then you will want to look at fork to spawn a semi-separate process within which you run would execute your cmd opt and arg with something similar to execv or execvp. Good luck, and post a comment if you have further questions.


Okay, that's the start of long story - made short abort parsing a command line in C ...

/**
* Helper function to parse the command line
* @param argc Argument Counter
* @param argv Argument Vector
* @param prog Program Instance Reference to fill with options
*/
bool parseCommandLine(int argc, char* argv[], DuplicateFileHardLinker* prog) {
  bool pathAdded = false;

  // Iterate over all arguments...
  for (int i = 1; i<argc; i++) {

    // Is argv a command line option?
    if (argv[i][0] == '-' || argv[i][0] == '/') {

      // ~~~~~~ Optionally Cut that part vvvvvvvvvvvvv for sake of simplicity ~~~~~~~
      // Check for longer options
      if (stricmp( &argv[i][1], "NoFileName") == 0  ||
          strcmp( &argv[i][1], "q1"         ) == 0 ) {

        boNoFileNameLog = true;

      } else if (strcmp( &argv[i][1], "HowAreYou?") == 0 ) {
          logInfo( "SECRET FOUND: Well - wow I'm glad ya ask me.");
      } else {


        // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        // Now here comes the main thing:
        //

        // Check for one-character options
        while (char option = *++argv[i]) {

          switch (option) {
          case '?':
            // Show program usage

            logInfo(L"Options:");
            logInfo(L"  /q\t>Quite mode");
            logInfo(L"  /v\t>Verbose mode");
            logInfo(L"  /d\t>Debug mode");
            return false;

            // Log options
          case 'q':
            setLogLevel(LOG_ERROR);
            break;

          case 'v':
            setLogLevel(LOG_VERBOSE);
            break;

          case 'd':
            setLogLevel(LOG_DEBUG);
            break;

          default:
            logError(L"'%s' is an illegal command line option!"
                      "  Use /? to see valid options!", option);
            return false;
          } // switch one-char-option
        } // while one-char-options
      }  // else one vs longer options
    } // if isArgAnOption

    //
    // ^^^^^^^^^^^^^^^^^^^^^^^^^^^  So that's it! ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    // What follows now is are some useful extras...
    //
    else {

      // The command line options seems to be a path...
      WCHAR tmpPath[MAX_PATH_LENGTH];
      mbstowcs(tmpPath, argv[i], sizeof(tmpPath));

      // Check if the path is existing!
      //...

      prog->addPath(tmpPath); // Comment or remove to get a working example
      pathAdded = true;
    }
  }

  // Check for parameters
  if (!pathAdded) {
    logError("You need to specify at least one folder to process!\n"
             "Use /? to see valid options!");
    return false;
  }

  return true;
}


int main(int argc, char* argv[]) {

  try {
    // Parse the command line
    if ( !parseCommandLine(argc, argv, prog) ) {
      return 1;
    }

    // I know that sample is just to show how the nicely parse command-line arguments
    // So Please excuse more nice useful C-glatter that follows now...

  }
  catch ( LPCWSTR err ) {
    DWORD dwError = GetLastError();
    if ( wcslen(err) > 0 ) {
      if ( dwError != 0 ) {
        logError(dwError, err);
      }
      else {
        logError(err);
      }
    }
    return 2;
  }
}

#define LOG_ERROR                1
#define LOG_INFO                 0
#define LOG_VERBOSE             -1
#define LOG_DEBUG               -2

/** Logging level for the console output */
int logLevel = LOG_INFO;

void logError(LPCWSTR message, ...) {
  va_list argp;
  fwprintf(stderr, L"ERROR: ");
  va_start(argp, message);
  vfwprintf(stderr, message, argp);
  va_end(argp);
  fwprintf(stderr, L"\n");
}


void logInfo(LPCWSTR message, ...) {
  if ( logLevel <= LOG_INFO ) {
    va_list argp;
    va_start(argp, message);
    vwprintf(message, argp);
    va_end(argp);
    wprintf(L"\n");
  }
}

Note that this version will also support combining arguments: So instead of writing /h /s -> /hs will also work.

Sorry for being the n-th person posting here - however I wasn't really satisfied with all the stand-alone-versions I saw here. Well, the library ones are quiet nice. So I would prefer the libUCW option parser, Arg or Getopt over a home-made ones.

Note you may change:

*++argv[i] -> (++argv*)[0]

It is longer and less cryptic, but still cryptic.

Okay, let's break it down:

  1. argv[i]-> access i-th element in the argv-char pointer field

  2. ++*... -> will forward the argv-pointer by one char

  3. ... [0]-> will follow the pointer read the char

  4. ++(...) -> bracket are there so we'll increase the pointer and not the char value itself.

It is so nice that in C#, the pointers 'died' - long live the pointers!!


AnyOption is a C++ class for easy parsing of complex commandline options. It also parses options from a rsourcefile in option value pair format.

AnyOption implements the traditional POSIX style character options ( -n ) as well as the newer GNU style long options ( --name ). Or you can use a simpler long option version ( -name ) by asking to ignore the POSIX style options.


There are these tools in the GNU C Library, which includes GetOpt.

If you are using Qt and like the GetOpt interface, froglogic has published a nice interface here.


This is my favourite way of doing the command line, especially, but definitely not only when efficiency is an issue. It might seem overkill, but I think there are few disadvantages to this overkill.

Use gperf for efficient C/C++ command line processing

Disadvantages:

  • You have to run a separate tool first to generate the code for a hash table in C/C++
  • No support for specific command line interfaces. For example the posix shorthand system "-xyz" declaring multiple options with one dash would be hard to implement.

Advantages:

  • Your command line options are stored separately from your C++ code (in a separate configuration file, which doesn't need to be read at runtime, only at compile time).
  • All you have in your code is exactly one switch (switching on enum values) to figure out which option you have
  • Efficiency is O(n) where n is the number of options on the command line and the number of possible options is irrelevant. The slowest part is possibly the implementation of the switch (sometimes compilers tend to implement them as if else blocks, reducing their efficiency, albeit this is unlikely if you choose contiguous values, see: this article on switch efficiency )
  • The memory allocated to store the keywords is precisely large enough for the keyword set and no larger.
  • Also works in C

Using an IDE like eclipse you can probably automate the process of running gperf, so the only thing you would have to do is add an option to the config file and to your switch statement and press build...

I used a batch file to run gperf and do some cleanup and add include guards with sed (on the gperf generated .hpp file)...

So, extremely concise and clean code within your software and one auto-generated hash table file that you don't really need to change manually. I doubt if boost::program_options actually would beat that even without efficiency as a priority.


It's a bit too big to include in a Stack Overflow answer, but I made a library for defining commands lines declaratively. It takes advantage of the the C++14 ability to build up a class constructor by giving initial values to each member variable.

The library is mostly a base class. To define your command syntax, you declare a struct that derives from it. Here's a sample:

struct MyCommandLine : public core::CommandLine {
    Argument<std::string> m_verb{this, "program", "program.exe",
        "this is what my program does"};
    Option<bool> m_help{this, "help", false,
        "displays information about the command line"};
    Alias<bool> alias_help{this, '?', &m_help};
    Option<bool> m_demo{this, "demo", false,
        "runs my program in demonstration mode"};
    Option<bool> m_maximize{this, "maximize", false,
        "opens the main window maximized"};
    Option<int> m_loops{this, "loops", 1,
        "specifies the number of times to repeat"};
    EnumOption<int> m_size{this, "size", 3,
                           { {"s", 1},
                             {"small", 1},
                             {"m", 3},
                             {"med", 3},
                             {"medium", 3},
                             {"l", 5},
                             {"large", 5} } };
    BeginOptionalArguments here{this};
    Argument<std::string> m_file{this, "file-name", "",
        "name of an existing file to open"};
} cl;

The Argument, Option, and Alias class templates are declared in the scope of the CommandLine base class, and you can specialize them for your own types. Each one takes the this pointer, the option name, the default value, and a description for use in printing the command synopsis/usage.

I'm still looking to eliminate the need to sprinkle all the this pointers in there, but I haven't found a way to do it without introducing macros. Those pointers allow each member to register itself with the tables in the base class that drive the parsing.

Once you have an instance, there are several overloads of a method to parse the input from a string or a main-style argument vector. The parser handles both Windows-style and Unix-style option syntax.

if (!cl.Parse(argc, argv)) {
    std::string message;
    for (const auto &error : cl.GetErrors()) {
        message += error + "\n";
    }
    std::cerr << message;
    exit(EXIT_FAILURE);
}

Once it's parsed, you can access the value of any of the options using operator():

if (cl.m_help()) { std::cout << cl.GetUsage(); }
for (int i = 0; i < cl.m_loops(); ++i) { ... }

The whole library is only about 300 lines (excluding tests). The instances are a bit bloaty, since the parsing tables are part of the instance (rather than the class). But you generally only need one instance per program, and the convenience of this purely declarative approach is pretty powerful, and an instance can be reset simply by parsing new input.


Docopt has a C implementation that I thought was quite nice:

From a man-page standardized format describing command line options, docopt infers and creates an argument parser. This got started in Python; the Python version literally just parses the docstring and returns a dict. To do this in C takes a little more work, but it's clean to use and has no external dependencies.


Use getopt(), or perhaps getopt_long().

int iflag = 0;
enum { WORD_MODE, LINE_MODE } op_mode = WORD_MODE;  // Default set
int opt;

while ((opt = getopt(argc, argv, "ilw") != -1)
{
    switch (opt)
    {
    case 'i':
        iflag = 1;
        break;
    case 'l':
        op_mode = LINE_MODE;
        break;
    case 'w':
        op_mode = WORD_MODE;
        break;
    default:
        fprintf(stderr, "Usage: %s [-ilw] [file ...]\n", argv[0]);
        exit(EXIT_FAILURE);
    }
}

/* Process file names or stdin */
if (optind >= argc)
    process(stdin, "(standard input)", op_mode);
else
{
    int i;
    for (i = optind; i < argc; i++)
    {
        FILE *fp = fopen(argv[i], "r");
        if (fp == 0)
            fprintf(stderr, "%s: failed to open %s (%d %s)\n",
                    argv[0], argv[i], errno, strerror(errno));
        else
        {
            process(fp, argv[i], op_mode);
            fclose(fp);
        }
    }
 }

Note that you need to determine which headers to include (I make it 4 that are required), and the way I wrote the op_mode type means you have a problem in the function process() - you can't access the enumeration down there. It's best to move the enumeration outside the function; you might even make op_mode a file-scope variable without external linkage (a fancy way of saying static) to avoid passing it to the function. This code does not handle - as a synonym for standard input, another exercise for the reader. Note that getopt() automatically takes care of -- to mark the end of options for you.

I've not run any version of the typing above past a compiler; there could be mistakes in it.


For extra credit, write a (library) function:

int filter(int argc, char **argv, int idx, int (*function)(FILE *fp, const char *fn));

which encapsulates the logic for processing file name options after the getopt() loop. It should handle - as standard input. Note that using this would indicate that op_mode should be a static file scope variable. The filter() function takes argc, argv, optind and a pointer to the processing function. It should return 0 (EXIT_SUCCESS) if it was able to open all the files and all invocations of the function reported 0, otherwise 1 (or EXIT_FAILURE). Having such a function simplifies writing Unix-style 'filter' programs that read files specified on the command line or standard input.


Qt 5.2 comes with a command line parser API.

Small example:

#include <QCoreApplication>
#include <QCommandLineParser>
#include <QDebug>

int main(int argc, char **argv)
{
  QCoreApplication app(argc, argv);
  app.setApplicationName("ToolX");
  app.setApplicationVersion("1.2");

  QCommandLineParser parser;
  parser.setApplicationDescription("Tool for doing X.");
  parser.addHelpOption();
  parser.addVersionOption();
  parser.addPositionalArgument("infile",
      QCoreApplication::translate("main", "Input file."));

  QCommandLineOption verbose_opt("+",
      QCoreApplication::translate("main", "be verbose"));
  parser.addOption(verbose_opt);

  QCommandLineOption out_opt(QStringList() << "o" << "output",
      QCoreApplication::translate("main", "Output file."),
      QCoreApplication::translate("main", "filename"), // value name
      QCoreApplication::translate("main", "out")   // default value
      );
  parser.addOption(out_opt);

  // exits on error
  parser.process(app);

  const QStringList args = parser.positionalArguments();

  qDebug() << "Input files: " << args
    << ", verbose: " << parser.isSet(verbose_opt)
    << ", output: " << parser.value(out_opt)
    << '\n';
  return 0;
}

Example output

The automatically generated help screen:

$ ./qtopt -h
Usage: ./qtopt [options] infile
Tool for doing X.

Options:
  -h, --help               Displays this help.
  -v, --version            Displays version information.
  -+                       be verbose
  -o, --output   Output file.

Arguments:
  infile                   Input file.

Automatically generated version output:

$ ./qtopt -v
ToolX 1.2

Some real calls:

$ ./qtopt b1 -+ -o tmp blah.foo
Input files:  ("b1", "blah.foo") , verbose:  true , output:  "tmp"
$ ./qtopt          
Input files:  () , verbose:  false , output:  "out"

A parse error:

$ ./qtopt --hlp
Unknown option 'hlp'.
$ echo $?
1

Conclusion

If your program already use the Qt (>= 5.2) libraries, its command line parsing API is convenient enough to get the job done.

Be aware that builtin Qt options are consumed by QApplication before the option parser runs.


A simple solution is to put argv into a std::map for easy lookups:

map<string, string> argvToMap(int argc, char * argv[])
{
    map<string, string> args;

    for(int i=1; i<argc; i++) {
        if (argv[i][0] == '-') {
            const string key = argv[i];
            string value = "";
            if (i+1 < argc && argv[i+1][0] != '-') {
                value = string(argv[i+1]);
                i++;
            }

            args[key] = value;
        }
    }

    return args;
}

Example usage:

#include <map>
#include <string>
#include <iostream>

using namespace std;

map<string, string> argvToMap(int argc, char * argv[])
{
    map<string, string> args;

    for(int i=1; i<argc; i++) {
        if (argv[i][0] == '-') {
            const string key = argv[i];
            string value = "";
            if (i+1 < argc && argv[i+1][0] != '-') {
                value = string(argv[i+1]);
                i++;
            }

            args[key] = value;
        }
    }

    return args;
}

void printUsage()
{
    cout << "simple_args: A sample program for simple arg parsing\n"
            "\n"
            "Example usage:\n"
            "    ./simple_args --print-all --option 1 --flag 2\n";
}

int main(int argc, char * argv[])
{
    auto args = argvToMap(argc, argv);

    if (args.count("-h") || args.count("--help")) {
        printUsage();
    }
    else if (args.count("--print-all")) {
        for (auto const & pair: args)
            cout << "{" << pair.first << ": " << pair.second << "}\n";
    }

    return 0;
}

Output:

$ ./simple_args --print-all --option 1 --flag "hello world"
{--flag: hello world}
{--option: 1}
{--print-all: }

There are definitely significant limitations to this approach, but I found it struck a good balance of simplicity and utility.


If you don't want to use boost, I'd recommend this little helper class.


Try CLPP library. It's simple and flexible library for command line parameters parsing. Header-only and cross-platform. Uses ISO C++ and Boost C++ libraries only. IMHO it is easier than Boost.Program_options.

Library: http://sourceforge.net/projects/clp-parser

26 October 2010 - new release 2.0rc. Many bugs fixed, full refactoring of the source code, documentation, examples and comments have been corrected.


Try Boost::Program Options. It allows you to read and parse command lines as well as config files.


A command is basically a string. In general it can be split into two parts - the command's name and the command's arguments.

Example:

ls

is used for listing the contents of a directory:

user@computer:~$ ls
Documents Pictures Videos ...

The ls above is executed inside home folder of a user. Here the argument which folder to list is implicitly added to the command. We can explicitly pass some arguments:

user@computer:~$ ls Picture
image1.jpg image2.jpg ...

Here I have explicitly told ls which folder's contents I'd like to see. We can use another argument for example l for listing the details of each file and folder such as access permissions, size etc.:

user@computer:~$ ls Pictures
-rw-r--r-- 1 user user   215867 Oct 12  2014 image1.jpg
-rw-r--r-- 1 user user   268800 Jul 31  2014 image2.jpg
...

Oh, the size looks really weird (215867, 268800). Let's add the h flag for human-friendly output:

user@computer:~$ ls -l -h Pictures
-rw-r--r-- 1 user user  211K Oct 12  2014 image1.jpg
-rw-r--r-- 1 user user  263K Jul 31  2014 image2.jpg
...

Some commands allow their arguments to be combined (in the above case we might as well write ls -lh and we'll get the same output), using short (a single letter usually but sometimes more; abbreviation) or long names (in case of ls we have the -a or --all for listing all files including hidden ones with --all being the long name for -a) etc. There are commands where the order of the arguments is very important but there are also others where the order of the arguments is not important at all.

For example it doesn't matter if I use ls -lh or ls -hl however in the case of mv (moving/renaming files) you have less flexibility for your last 2 arguments that is mv [OPTIONS] SOURCE DESTINATION.

In order to get a grip of commands and their arguments you can use man (example: man ls) or info (example: info ls).

In many languages including C/C++ you have a way of parsing command line arguments that the user has attached to the call of the executable (the command). There are also numerous libraries available for this task since in its core it's actually not that easy to do it properly and at the same time offer a large amount of arguments and their varieties:

  • getopt
  • argp_parse
  • gflags
  • ...

Every C/C++ application has the so called entry point, which is basically where your code starts - the main function:

int main (int argc, char *argv[]) { // When you launch your application the first line of code that is ran is this one - entry point
    // Some code here
    return 0; // Exit code of the application - exit point
}

No matter if you use a library (like one of the above I've mentioned; but this is clearly not allowed in your case ;)) or do it on your own your main function has the two arguments:

  • argc - represents the number of arguments
  • argv - a pointer to an array of strings (you can also see char** argv which is basically the same but more difficult to use).

NOTE: main actually also has a third argument char *envp[] which allows passing environment variables to your command but this is a more advanced thing and I really don't think that it's required in your case.

The processing of command line arguments consists of two parts:

  1. Tokenizing - this is the part where each argument gets a meaning. Its the process of breaking your arguments list into meaningful elements (tokens). In the case of ls -l the l is not only a valid character but also a token in itself since it represents a complete, valid argument.

Here is an example how to output the number of arguments and the (unchecked for validity) characters that may or may not actually be arguments:

#include <iostream>
using std::cout;
using std::endl;

int main (int argc, char *argv[]) {
    cout << "Arguments' count=%d" << argc << endl;

    // First argument is ALWAYS the command itself
    cout << "Command: " << argv[0] << endl;

    // For additional arguments we start from argv[1] and continue (if any)
    for (int i = 1; i < argc; i++) {
        cout << "arg[" << i << "]: " << argv[i] << endl;
    }

    cout << endl;
    return 0;
}
  1. Parsing - after acquiring the tokens (arguments and their values) you need to check if your command supports these. For example:

    user@computer:~$ ls -y
    

    will return

    ls: invalid option -- 'y'
    Try 'ls --help' for more information.
    

    This is because the parsing has failed. Why? Because y (and -y respectively; note that -, --, : etc. is not required and its up to the parsing of the arguments whether you want that stuff there or not; in Unix/Linux systems this is a sort of a convention but you are not bind to it) is an unknown argument for the ls command.

For each argument (if successfully recognized as such) you trigger some sort of change in your application. You can use an if-else for example to check if a certain argument is valid and what it does followed by changing whatever you want that argument to change in the execution of the rest of your code. You can go the old C-style or C++-style:

* `if (strcmp(argv[1], "x") == 0) { ... }` - compare the pointer value
* `if (std::string(argv[1]) == "x") { ... }` - convert to string and then compare

I actually like (when not using a library) to convert argv to an std::vector of strings like this:

std::vector<std::string> args(argv, argv+argc);
for (size_t i = 1; i < args.size(); ++i) {
    if (args[i] == "x") {
        // Handle x
    }
    else if (args[i] == "y") {
        // Handle y
    }
    // ...
}

The std::vector<std::string> args(argv, argv+argc); part is just an easier C++-ish way to handle the array of strings since char * is a C-style string (with char *argv[] being an array of such strings) which can easily be converted to a C++ string that is std::string. Then we can add all converted strings to a vector by giving the starting address of argv and then also pointing to its last address namely argv + argc (we add argc number of string to the base address of argv which is basically pointing at the last address of our array).

Inside the for loop above you can see that I check (using simple if-else) if a certain argument is available and if yes then handle it accordingly. A word of caution: by using such a loop the order of the arguments doesn't matter. As I've mentioned at the beginning some commands actually have a strict order for some or all of their arguments. You can handle this in a different way by manually calling the content of each args (or argv if you use the initial char* argv[] and not the vector solution):

// No for loop!
if (args[1] == "x") {
    // Handle x
}
else if (args[2] == "y") {
    // Handle y
}
// ...

This makes sure that at position 1 only the x will be expected etc. The problem with this is that you can shoot yourself in the leg by going out of bounds with the indexing so you have to make sure that your index stays within the range set by argc:

if (argc > 1 && argc <= 3) {
    if (args[1] == "x") {
        // Handle x
    }
    else if (args[2] == "y") {
        // Handle y
    }
}

The example above makes sure you have content at index 1 and 2 but not beyond.

Last but not least the handling of each argument is a thing that is totally up to you. You can use boolean flags that are set when a certain argument is detected (example: if (args[i] == "x") { xFound = true; } and later on in your code do something based on the bool xFound and its value), numerical types if the argument is a number OR consists of number along with the argument's name (example: mycommand -x=4 has an argument -x=4 which you can additionally parse as x and 4 the last being the value of x) etc. Based on the task at hand you can go crazy and add an insane amount of complexity to your command line arguments.

Hope this helps. Let me know if something is unclear or you need more examples.


I've found Gengetopt to be quite useful - you specify the options you want with a simple configuration file, and it generates a .c/.h pair that you simply include and link with your application. The generated code makes use of getopt_long, appears to handle most common sorts of command line parameters, and it can save a lot of time.

A gengetopt input file might look something like this:

version "0.1"
package "myApp"
purpose "Does something useful."

# Options
option "filename" f "Input filename" string required
option "verbose" v "Increase program verbosity" flag off
option "id" i "Data ID" int required
option "value" r "Data value" multiple(1-) int optional 

Generating the code is easy and spits out cmdline.h and cmdline.c:

$ gengetopt --input=myApp.cmdline --include-getopt

The generated code is easily integrated:

#include <stdio.h>
#include "cmdline.h"

int main(int argc, char ** argv) {
  struct gengetopt_args_info ai;
  if (cmdline_parser(argc, argv, &ai) != 0) {
    exit(1);
  }
  printf("ai.filename_arg: %s\n", ai.filename_arg);
  printf("ai.verbose_flag: %d\n", ai.verbose_flag);
  printf("ai.id_arg: %d\n", ai.id_arg);
  int i;
  for (i = 0; i < ai.value_given; ++i) {
    printf("ai.value_arg[%d]: %d\n", i, ai.value_arg[i]);
  }
}

If you need to do any extra checking (such as ensuring flags are mutually exclusive), you can do this fairly easily with the data stored in the gengetopt_args_info struct.


I'd suggest using a library. There's the classic and venerable getopt and I'm sure others.


    /*
      Here's a rough one not relying on any libraries.
      Example:
      -wi | -iw //word case insensitive
      -li | -il //line case insensitive
      -- file  //specify the first filename (you could just get the files
      as positional arguments in the else statement instead)
      PS: don't mind the #define's, they're just pasting code :D
    */
    #ifndef OPT_H
    #define OPT_H

    //specify option requires argument
    #define require \
      optarg = opt_pointer + 1; \
      if (*optarg == '\0') \
      { \
        if (++optind == argc) \
          goto opt_err_arg; \
        else \
          optarg = argv[optind]; \
      } \
      opt_pointer = opt_null_terminator;

    //start processing argv
    #define opt \
    int   optind                 = 1; \
    char *opt_pointer            = argv[1]; \
    char *optarg                 = NULL; \
    char  opt_null_terminator[2] = {'\0','\0'}; \
    if (0) \
    { \
      opt_err_arg: \
        fprintf(stderr,"option %c requires argument.\n",*opt_pointer); \
        return 1; \
      opt_err_opt: \
        fprintf(stderr,"option %c is invalid.\n",*opt_pointer); \
        return 1; \
    } \
    for (; optind < argc; opt_pointer = argv[++optind]) \
      if (*opt_pointer++ == '-') \
      { \
        for (;;++opt_pointer) \
          switch (*opt_pointer) \
          {

    //stop processing argv
    #define done \
          default: \
            if (*opt_pointer != '\0') \
              goto opt_err_opt; \
            else \
              goto opt_next; \
            break; \
          } \
        opt_next:; \
      }
    #endif //opt.h

    #include <stdio.h>
    #include "opt.h"
    int
    main (int argc, char **argv)
    {
      #define by_character 0
      #define by_word      1
      #define by_line      2
      int cmp = by_character;
      int case_insensitive = 0;
      opt
      case 'h':
        puts ("HELP!");
        break;
      case 'v':
        puts ("fileCMP Version 1.0");
        break;
      case 'i':
        case_insensitive = 1;
        break;
      case 'w':
        cmp = by_word;
        break;
      case 'l':
        cmp = by_line;
        break;
      case '-':required
        printf("first filename: %s\n", optarg);
        break;
      done
      else printf ("Positional Argument %s\n", argv[optind]);
      return 0;
    }

With C++, the answer is usually in Boost...

Boost.Program Options


I'd suggest using a library. There's the classic and venerable getopt and I'm sure others.


#include <stdio.h>

int main(int argc, char **argv)
{
    size_t i;
    size_t filename_i = -1;

    for (i = 0; i < argc; i++)
    {
        char const *option =  argv[i];
        if (option[0] == '-')
        {
            printf("I am a flagged option");
            switch (option[1])
            {
                case 'a':
                    /*someting*/
                    break;
                case 'b':
                    break;
                case '-':
                    /* "--" -- the next argument will be a file.*/
                    filename_i = i;
                    i = i + 1;
                    break;
                default:
                    printf("flag not recognised %s", option);
                    break;
            }
        }
        else
        {   
            printf("I am a positional argument");
        }

        /* At this point, if -- was specified, then filename_i contains the index
         into argv that contains the filename. If -- was not specified, then filename_i will be -1*/
     }
  return 0;
}