argv[] comparison

K

kaferro

What is the safest way to make an argv[] comparison? The code below
works.

#include <iostream>
#include <string>

using namespace std;

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

if(argc>1)
test = argv[1];

if(test=="NKDT")
cout << "\nComparison is true. Have program do something.\n";
else
cout << "\nComparison is false. Have program do something else.\n";

return 0;
}
 
A

Alf P. Steinbach

* (e-mail address removed):
What is the safest way to make an argv[] comparison? The code below
works.

#include <iostream>
#include <string>

using namespace std;

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

if(argc>1)
test = argv[1];

if(test=="NKDT")
cout << "\nComparison is true. Have program do something.\n";
else
cout << "\nComparison is false. Have program do something else.\n";

return 0;
}

Do the following:

#include <iostream>

#include <cstddef>
#include <string>
#include <vector>
#include <stdexcept>

typedef std::vector<std::string> StringVector;

bool throwX( char const s[] ) { throw std::runtime_error( s ); }

void cppMain( StringVector const& arguments )
{
arguments.size() > 1
|| throwX( "usage: myprog ARG1" );

if( arguments.at(1) == "NKDT" )
{
// Do something.
}
else
{
// Do something else.
}
}

int main( int n, char* a[] )
{
try
{
cppMain( StringVector( a, a+n ) );
return EXIT_SUCCESS;
}
catch( std::exception const& x )
{
std::cerr << "!" << x.what() << std::endl;
return EXIT_FAILURE;
}
}
 
D

dave_mikesell

* (e-mail address removed):




What is the safest way to make an argv[] comparison? The code below
works.
#include <iostream>
#include <string>
using namespace std;
int main(int argc, char *argv[])
{
string test;
if(argc>1)
test = argv[1];
if(test=="NKDT")
cout << "\nComparison is true. Have program do something.\n";
else
cout << "\nComparison is false. Have program do something else.\n";
return 0;
}

Do the following:

<snip>

What was wrong with the OP's solution, which appeared to be much more
concise?
 
A

Alf P. Steinbach

* (e-mail address removed):
* (e-mail address removed):
What is the safest way to make an argv[] comparison? The code below
works.
#include <iostream>
#include <string>
using namespace std;
int main(int argc, char *argv[])
{
string test;
if(argc>1)
test = argv[1];
if(test=="NKDT")
cout << "\nComparison is true. Have program do something.\n";
else
cout << "\nComparison is false. Have program do something else.\n";
return 0;
}
Do the following:

<snip>

What was wrong with the OP's solution, which appeared to be much more
concise?

Probably directly wrong: always indicating success for the program
execution. Also probably directly wrong: doesn't handle exceptions.
However, one might design a program so that no exception should ever
propagate up to main and if it does one wants termination for ease of
debugging, not a report and failure indication. So it depends on design
and methodology and toolchain and to some extent personal preference.
But I don't think the lack of exception handling here was intentional.

Ungood: the main code has direct access to argc and argv, when the aim
is to handle them in "the safest way" (giving access is unsafe). Also
ungood in general: "using namespace std:;". Also ungood: not using
curly braces for nested statements (just about any style guideline will
tell you to use them, always, in order to support maintenance).

Appearance of conciseness: all of the OP's code is program-specific,
whereas the code I listed is mostly boilerplate, a kind of
micro-framework for this particular kind of small student program or
professional's check-it-out program or single-use personal tool program.
For consisness one could write e.g. (doing the /same/ as the OP's code)

#include <string>
#include <iostream>
int main( int n, char* a[] )
{
using namespace std;
n > 1 && std::string( a[1] ) == "NKDT"
? cout << "\nComparison is true. Something.\n"
: cout << "\nComparison is false. Something else.\n";
}

getting rid of the local variable 'test' and also the 'return 0' which
is implied (it's the default) in 'main', and just to make it extra
concise I also removed that darned 'else' which otherwise would use up a
very expensive line, and the keyword 'if' which is so much to read. I
simply don't understand why so many programmers think conciseness is a
goal. They just end up not understanding their own code.
 
J

James Kanze

What is the safest way to make an argv[] comparison? The code below
works.
#include <iostream>
#include <string>
using namespace std;
int main(int argc, char *argv[])
{
string test;

if(argc>1)
test = argv[1];

if(test=="NKDT")
cout << "\nComparison is true. Have program do something.\n";
else
cout << "\nComparison is false. Have program do something else.\n";
return 0;
}

It depends on context. For simply "quicky" programs, I just do
it as I did in C, something like:

if ( argc > 1 && strcmp( argc[ 1 ], "NKDT" ) == 0 ) {
// ...
}

As soon as the program ceases to be trivial, however, I'll use a
library based solution which strips out the options, and exposes
the remaining arguments as a std::vector<std::string>, or
something similar. Thus, my own code would be something like:

int
main( int argc, char** argv )
{
Gabi::CommandLine& args( Gabi::CommandLine::instance() ) ;
args.parse( argc, argv ) ;
if ( args.size() > 1 && args[ i ] == "NKDT" ) {
// ...
} else {
// ...
}
return Gabi::programStatus::returnCode() ;
}

Such binary selections are more often handled by means of
options, however:

int
main( int argc, char** argv )
{
Gabi::BooleanOption isNKDT( "NKDT" ) ;
Gabi::CommandLine& args( Gabi::CommandLine::instance() ) ;
args.parse( argc, argv ) ;
if ( isNKDT ) {
// ...
} else {
// ...
}
return Gabi::programStatus::returnCode() ;
}
 
G

Gianni Mariani

What is the safest way to make an argv[] comparison? The code below
works.

#include <iostream>
#include <string>

using namespace std;

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

if(argc>1)
test = argv[1];

if(test=="NKDT")
cout << "\nComparison is true. Have program do something.\n";
else
cout << "\nComparison is false. Have program do something else.\n";

return 0;
}

Use a command line parser like the one in CommmonC++ :)

#include <cc++/common.h>

ost::CommandOptionArg NKDT_Option(
"NKDT", "p", "--NKDT is for super stuff"
);

ost::CommandOptionNoArg helparg(
"help", "?", "Print help usage"
);

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

CommandOptionParse * args = ost::makeCommandOptionParse(
argc, argv,
"This command is so special !"
);

if ( helparg.numSet ) {
cerr << args->printUsage();
::exit(0);
}

if ( NKDT_Option.numSet )
{
cout << "\nHave program do something.\n";
return result;
} else {
cout << "\nHave program do something else.\n";
return result;
}
}

.....

The nice thing about this is that anywhere in your code, you can add
ost::CommandOptionXXX options and they're picked up automatically. So
main does not get complicated with every possible option. The command
option parser automatically pulls together all the parameters to create
a usage.

It's a little outdated in that it was written before std::string was
working properly on most compilers so it use C style stings everywhere.
 
D

dave_mikesell

getting rid of the local variable 'test' and also the 'return 0' which
is implied (it's the default) in 'main', and just to make it extra
concise I also removed that darned 'else' which otherwise would use up a
very expensive line, and the keyword 'if' which is so much to read.

The OP's example was nothing like that. Conciseness does not
necessarily lead to obfuscation, your strawman notwithstanding.
I simply don't understand why so many programmers think conciseness is a
goal.

Nor I why so many tend to overcomplicate simple solutions to simple
problems.
They just end up not understanding their own code.

Same thing happens with over-engineered code.
 
A

Alf P. Steinbach

* (e-mail address removed):
The OP's example was nothing like that. Conciseness does not
necessarily lead to obfuscation, your strawman notwithstanding.


Nor I why so many tend to overcomplicate simple solutions to simple
problems.

It is a "standard" solution. I think you'll find it somewhere at the
beginning of Accelerated C++. Although I don't have that book.

If you have questions about it I'll be happy to answer them.
 
L

Lionel B

* (e-mail address removed):
What is the safest way to make an argv[] comparison? The code below
works.

#include <iostream>
#include <string>

using namespace std;

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

if(argc>1)
test = argv[1];

if(test=="NKDT")
cout << "\nComparison is true. Have program do something. \n";
else
cout << "\nComparison is false. Have program do something else.\n";

return 0;
}

Do the following:

[snip]

You appear to assume that an exception should be thrown if the command
line does not have a particular form. I see no such requirement expressed
by the OP who does not, in fact, suggest that the "false" comparison is
in any way "exceptional".
 
G

Gianni Mariani

The OP's example was nothing like that. Conciseness does not
necessarily lead to obfuscation, your strawman notwithstanding.


Nor I why so many tend to overcomplicate simple solutions to simple
problems.


Same thing happens with over-engineered code.

std::vector is part of the standard.
std::string is part of the standard.

What about these is complex ?

There exists a minimum complexity. employing char * is usually bad news
and is prone to far more subtle complexity that is exemplified by the
OP's question.

Alf's code does more like what you would expect.
 
J

Juha Nieminen

Alf said:
#include <iostream>

#include <cstddef>
#include <string>
#include <vector>
#include <stdexcept>

typedef std::vector<std::string> StringVector;

bool throwX( char const s[] ) { throw std::runtime_error( s ); }

void cppMain( StringVector const& arguments )
{
arguments.size() > 1
|| throwX( "usage: myprog ARG1" );

if( arguments.at(1) == "NKDT" )
{
// Do something.
}
else
{
// Do something else.
}
}

int main( int n, char* a[] )
{
try
{
cppMain( StringVector( a, a+n ) );
return EXIT_SUCCESS;
}
catch( std::exception const& x )
{
std::cerr << "!" << x.what() << std::endl;
return EXIT_FAILURE;
}
}

Why such a complicated solution to such a simple problem? How about
simply:

int main(int argc, char* argv[])
{
std::vector<std::string> cmdLine(argv, argv+argc);

if(cmdLine.size() > 1 && cmdLine[1] == "NKDT")
{
// Do something
}
else
{
// Do something else
}
}
 
D

dave_mikesell

(e-mail address removed) wrote:
std::vector is part of the standard.
std::string is part of the standard.

What about these is complex ?

There exists a minimum complexity. employing char * is usually bad news
and is prone to far more subtle complexity that is exemplified by the
OP's question.

Not sure what you mean here - the OP's solution creates a std::string
from argv[1]. If he only cares about argv[1], his solution seemed
fine to me re: parsing the command line.
 
D

dave_mikesell

(e-mail address removed) wrote:
std::vector is part of the standard.
std::string is part of the standard.

What about these is complex ?

There exists a minimum complexity. employing char * is usually bad news
and is prone to far more subtle complexity that is exemplified by the
OP's question.

Not sure what you mean here - the OP's solution creates a std::string
from argv[1]. If he only cares about argv[1], his solution seemed
fine to me re: parsing the command line.
 
A

Alf P. Steinbach

* Juha Nieminen:
Alf said:
#include <iostream>

#include <cstddef>
#include <string>
#include <vector>
#include <stdexcept>

typedef std::vector<std::string> StringVector;

bool throwX( char const s[] ) { throw std::runtime_error( s ); }

void cppMain( StringVector const& arguments )
{
arguments.size() > 1
|| throwX( "usage: myprog ARG1" );

if( arguments.at(1) == "NKDT" )
{
// Do something.
}
else
{
// Do something else.
}
}

int main( int n, char* a[] )
{
try
{
cppMain( StringVector( a, a+n ) );
return EXIT_SUCCESS;
}
catch( std::exception const& x )
{
std::cerr << "!" << x.what() << std::endl;
return EXIT_FAILURE;
}
}

Why such a complicated solution to such a simple problem? How about
simply:

int main(int argc, char* argv[])
{
std::vector<std::string> cmdLine(argv, argv+argc);

if(cmdLine.size() > 1 && cmdLine[1] == "NKDT")
{
// Do something
}
else
{
// Do something else
}
}

Yours is not reusable without changes. Note that the code you put in
'main' is the code in 'cppMain' (and all code that is program-specific,
i.e. that has to be written), except that 'cppMain' is safer because it
doesn't give access to the C-style arguments and because it can safely
throw exceptions. Always think about reusing code instead of inventing
the wheel over and over with just slight details different.
 
A

Alf P. Steinbach

* Lionel B:
* (e-mail address removed):
What is the safest way to make an argv[] comparison? The code below
works.

#include <iostream>
#include <string>

using namespace std;

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

if(argc>1)
test = argv[1];

if(test=="NKDT")
cout << "\nComparison is true. Have program do something. \n";
else
cout << "\nComparison is false. Have program do something else.\n";
return 0;
}
Do the following:

[snip]

You appear to assume that an exception should be thrown if the command
line does not have a particular form. I see no such requirement expressed
by the OP who does not, in fact, suggest that the "false" comparison is
in any way "exceptional".

No, using an exception is just the simple and safe way to do things in
that context.

On the other hand, I do assume that any actual program will need to deal
with exceptions; otherwise you're using C++ as just a better C.

There are more options for that than just the code shown, but if you're
going to write a little toy program it's good boilerplate code.
 
D

dave_mikesell

(e-mail address removed) wrote:
std::vector is part of the standard.
std::string is part of the standard.

What about these is complex ?

There exists a minimum complexity. employing char * is usually bad news
and is prone to far more subtle complexity that is exemplified by the
OP's question.

Not sure what you mean here - the OP's solution creates a std::string
from argv[1]. If he only cares about argv[1], his solution seemed
fine to me re: parsing the command line.
 
L

Lionel B

* Lionel B:
* (e-mail address removed):
What is the safest way to make an argv[] comparison? The code below
works.

#include <iostream>
#include <string>

using namespace std;

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

if(argc>1)
test = argv[1];

if(test=="NKDT")
cout << "\nComparison is true. Have program do something. \n";
else
cout << "\nComparison is false. Have program do something else.\n";
return 0;
}
Do the following:

[snip]

You appear to assume that an exception should be thrown if the command
line does not have a particular form. I see no such requirement
expressed by the OP who does not, in fact, suggest that the "false"
comparison is in any way "exceptional".

No, using an exception is just the simple and safe way to do things in
that context.

Well, it is *a* simple(ish) and safe way.
On the other hand, I do assume that any actual program will need to deal
with exceptions;

Beside the point... the fact remains that (as far as we can know) the
"false" branch in the OP's code may be perfectly "unexceptional". In fact
his/her action for the "false" branch was "Have program do something
else". That doesn't (to me) say "throw exception".
otherwise you're using C++ as just a better C.

A perfectly honourable use for C++ ;-)
There are more options for that than just the code shown, but if you're
going to write a little toy program it's good boilerplate code.

Sure, it's a fine idiom if deployed as the OP intended, which I'm not
convinced it was.
 
A

Alf P. Steinbach

* Lionel B:
Beside the point... the fact remains that (as far as we can know) the
"false" branch in the OP's code may be perfectly "unexceptional". In fact
his/her action for the "false" branch was "Have program do something
else". That doesn't (to me) say "throw exception".

I'm not sure that the effect of the OP's code was intentional, and the
question was how to deal with argv, not how to replicate the effect of
the original code (still I posted such replication else-thread).

Anyway, it's silly and just plain argumentative to object to getting too
generally useful code.

If you'd objected that the code was too special purpose it could have
been a valid objection.
 
J

Juha Nieminen

Alf said:
Yours is not reusable without changes.

"My" version consists basically of two (2) lines: One line which
creates the vector, and another with compares the first command-line
argument. Your requirement of "reusability" for two lines of code seems
quite odd to me. It doesn't make too much sense.

As for "without changes", that's even odder. Your solution requires
exactly as many changes to be "reusable" as mine, namely changing the
string being compared.
Note that the code you put in
'main' is the code in 'cppMain' (and all code that is program-specific,
i.e. that has to be written), except that 'cppMain' is safer because it
doesn't give access to the C-style arguments and because it can safely
throw exceptions.

Do you understand the concept of over-engineering?
Always think about reusing code instead of inventing
the wheel over and over with just slight details different.

Having to write 2 lines of code is "inventing the wheel over and
over". Right.
 
A

Alf P. Steinbach

* Juha Nieminen:
"My" version consists basically of two (2) lines: One line which
creates the vector, and another with compares the first command-line
argument. Your requirement of "reusability" for two lines of code seems
quite odd to me. It doesn't make too much sense.

Yes, it's true, what you're saying doesn't make sense. And the reason
that what you're saying doesn't make sense, is that you have based your
reasoning on false assumptions in order to fit a preconceived senseless
conclusion. The reusability is not for two problem-specific lines of
code: it's for argument packaging, exception handling (more generally
failure handling), main return codes, and removal of access to low-level
stuff.

And that's everything except the code between the braces in 'cppMain'.

Not that your code is much inferior, since we're talking about two
extremely trivial and short programs, but it's based on reinventing the
wheel. Except if you like spaghetti and bug-fixing, the above has to
be done for any program that does anything real. Even though we're
still talking about novice programs, toy programs, small test programs.

As for "without changes", that's even odder. Your solution requires
exactly as many changes to be "reusable" as mine, namely changing the
string being compared.

That's incorrect. And the reason it's incorrect is that you envision a
specific case of reuse where your code conceivably could be reused
mostly as-is, in order to fit your preconceived incorrect conclusion.
Out of the infinitely many programs one can make you've chosen an
extremely small set parameterized by one datum, and you incorrectly call
that reusability.

Do you understand the concept of over-engineering?


Having to write 2 lines of code is "inventing the wheel over and
over". Right.

I'm sorry, what you're writing is not meaningful.

Nobody forces you to use save work by using that little boilerplate code.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,995
Messages
2,570,236
Members
46,825
Latest member
VernonQuy6

Latest Threads

Top