tags:

views:

1116

answers:

8

Suggestions for command-line argument processing in C++ efficiently:

Note: Windows specific only

 1:     #include <iostream.h>
 2:     int main(int argc, char **argv)

Instead of, for example:

 if ( argc != 3 )  {
      ....
 }

Regards

+12  A: 

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

Boost.Program Options

Ferruccio
Boost OK for windows env?
Aaron
Boost is ok for Windows.
Parappa
OK I'll try, *kind* regards Parappa
Aaron
+4  A: 

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

Aaron Maenpaa
Available on windows?
Allain Lalonde
or getopt_long if you've got it
robottobor
only *nix based systems iirc
Kevin Loney
I'm not sure if getopt is available on windows. I know it is in C on GNU
Aaron
my co-worker used it on windows. im quite sure it's available on windows
Johannes Schaub - litb
I believe you have to write your own version...
Aaron
A: 

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

Stefan
+8  A: 

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 (vector<string>::iterator 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.]

j_random_hacker
Do you have a brief demonstration? Regards
Aaron
Added a simple example. Really all the vector<string> buys you is simple comparisons with == and convenient by-value copying.
j_random_hacker
This doesn't help to do anything that can't be already done with argc/argv.
brofield
@brofield: Sure, it doesn't change the world. But I find the == and value semantics simplify things enough that I keep using it.
j_random_hacker
@brofield: honestly, this is good!
Aaron
@j_random_hacker - what if I want to remember the order of the arguments? For instance, if the user typed `mycommand.exe -h file.csv`, I want to tell them that they are not using the utility correctly and why (should not supply a file name if they are just using the version). This example is rather simple, but I can think of more convoluted flags. The end result would be: sometimes the order does matter, and sometimes it does not. So ... how should I proceed then? Let me know if you have a question about my question.
Hamish Grubijan
@Hamish: I'm a bit confused -- loading the strings into a vector doesn't "lose" their order. You can still access the ith argument with `args[i]` (in fact I often do this myself, as the comment in my code snippet says). The iterator style is just a bit more convenient if you only need to deal with one at a time. Does that answer your question?
j_random_hacker
@j_random_hacker Ah, yes, lol. Case closed.
Hamish Grubijan
A: 

Your question is redundant with this one.

Luc Hermitte
This isn't an answer; it's a comment.
Evan Kroske
+4  A: 

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.

brofield
+2  A: 

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.

ufotds
A: 

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.

Denis Shevchenko