Pergunta

I have a program (myprogram) that takes a file for input and creates another file for output. The syntax is:

myprogram inputfile outputfile

It looks something like this:

int main ( int argc, char *argv[] )
{
...  
if ( argc != 3 ) {
    cout<<"wrong number of arguments"<< endl; return 1;}
   }
myInputFile = argv[1];
myOutputFile = argv[2];
...
}

So here I have argv[1] being the inputfile.I would now like to add some options to the syntax. So, for example, I would like myprogram -a inputfile outputfile as an option. The number of options will vary.

That means that the filenames will depend on the number of arguments.

What is the smartest way to do this in the code? I can see that one would just take the last two arguments as the filenames and then assume that the arguments before that are the options (so something like myInputFile = argv[argc - 1]. This doesn't quite feel right because I end up with a lot of if ... then statements.

So my question is: How does one best deal with a variable number of arguments?

Foi útil?

Solução

How about that in case you do not want to use libraries:

char* myInputFile = NULL ;
char* myOutputFile = NULL ;
bool  option_a = false ;
int   argi = 1 ;

while ( argi < argc )
{
   const char* args = argv[ argi++ ] ;

   switch ( *args )
   {
      case '-' : /* option/switch */
         if ( strcmp( args, "-a" ) == 0 )
            option_a = true ;
         else
         {
            std::cerr << "Unknow option " << args << "\n" ;
            exit( 1 ) ;
         }
         break ;

      default :
         if ( myInputFile == NULL )
            myInputFile = args ;
         else if ( myOutputFile == NULL )
            myOutputFile = args ;
         else
         {
            std::cerr << "Unexpected argument " << args << "\n" ;
            exit( 1 );
         }
         break ;
   }
}

At the end, when you process all your arguments you can do some final checking like, for example, testing if the input file and output file were set:

if ( myInputFile == NULL )
{
    std::cerr << "Input file missing!\n" ;
    exit( 1 ) ;
}
...

You could also put all your arguments into a structure instead of having them separately:

struct options_t
{
    char* myInputFile ;
    char* myOutputFile ;
    bool  option_a ;

    options_t() : myInputFile(), myOutputFile(), option_a() {}
} ;

This way you can pass all arguments down to your functions instead of listing them one by one.

Just a thought...

Outras dicas

The most common way is to write a special method for handling the command line arguments. You give it argc and argv and it returns a structured set of data values. e.g.

struct commands
{
    char* InputFile;
    char* OutputFile;
    bool WhateverAMeans;
};

This way your main loop has a sufficient list of things it requires and doesn't require tons of loops.

Typically your method would use a for loop to iterate over the arguments to fill in the commands.

Alternatively there exist helper classes that do this work for you, although I cannot recommend any having not done this in a long time.

If you don't mind I'd suggest a library that deals w/ all these issues. Try Boost.Program Options. It might look too complex than you expected but it's powerful enough. Also there're a lot C libraries, like getopt, popt and many others

Look at boost::program_options, very useful and clean tool for that. I also used Poco::OptionSet, but it wasn't so clean for me, as boost. Both Poco and boost need to be build by you, but if you never used any of them - that is good chance to start, they both are awesome.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top