Sign in to follow this  

Passing Arguments to an Executable

This topic is 2655 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hi,

I'm not new to programming, but I am fairly new to C/C++.

I am trying to make an executable that can be called as so:
LinearResample.exe <input> <new width> <new height> <output>


I've never done anything of this sort before. I assume that this syntax would be handled through the argv statement?

So, for the above example, would argc be 4 and argv a pointer to an array, where array[0]==<input>, array[1]==<new width>, etc.?

Again, never done this before, so it would be great to know sorta what I'm doing.

Thanks,
G

Share this post


Link to post
Share on other sites
Quote:
Original post by SiCrane
Actually, the first parameter doesn't have to be the exe file name. On most platforms there are ways to invoke the program that will change argv[0] to arbitrary strings.


Really? How would it be done on, say Win32/Win64? (Just out of curiosity [smile])

Share this post


Link to post
Share on other sites
Plain old CreateProcess:
Quote:

The flexibility of the CreateProcess() function (and a possible point of confusion) arises when you pass a valid string pointer to both the ApplicationName and CommandLine parameters. This allows you to specify the application to be executed as well as the complete command line that is passed to the application. One might assume that the command line passed to the created application is a composite of the ApplicationName and CommandLine parameters, but this is not the case. As a result, a process created by CreateProcess can receive a value other than its .exe name as its "argv[0]" parameter. The following is an example of a call to CreateProcess that produces this "abnormal" behavior:

Share this post


Link to post
Share on other sites
Awesome.

So, what happens if I want to pass in a number, like 512, to the argument list?

This should be equivalent to:
char new_width = 512;

. . . which my compiler tells me results in a truncation/possible loss of data. Which makes sense, because 512 can't fit in a byte.

So . . . what do I do about this?

Thanks,
-G

Share this post


Link to post
Share on other sites
This is entirely from memory so may not compile or run [wink]

#include <sstream>
#include <iostream>

int main(int argc, char** argv)
{
int value = 0;

if(argc > 1)
{
std::stringstream converter;
converter << argv[1];
converter >> value;
}

std::cout << "Passed numeric value: " << value << std::endl;
}

Share this post


Link to post
Share on other sites
Quote:
Original post by Geometrian
Well, the first and fourth arguments actually are chars and the second and third arguments actually are ints.



Uh... so... index into the array to get the second and third elements, and pass those to the converter/lexical_cast instead of the first one. That's just general programming, nothing magical about C (or C++, which is what I'm guessing you're actually using).

Share this post


Link to post
Share on other sites
Quote:

Well, the first and fourth arguments actually are chars and the second and third arguments actually are ints.

Read them as integers, do a range test on them and if safe convert them to chars. I assume when you say "chars" you mean byte-sized integral values, and not character values.

For characters, its pretty trivial (char c = argv[N][0] with a little error checking).

Share this post


Link to post
Share on other sites
... I think you don't understand what it means for a variable to be of the type char, based on how you are writing.

A char is an integral type. It belongs to the same family as short, int, long and long long. It is used to represent a single character of non-Unicode text, via a mapping such as ASCII.

It does not represent a string in any way. The argv parameter you get in main() is a char**; that is, a pointer to a sequence of char*'s, each of which is a pointer to a sequence of chars. Each of these sequences of chars, each ending with a '\0' character (a byte with a value of zero), represents a string. (These characters allow the code to determine where the string ends.)

In C++, we have a superior representation for strings, called std::string. We also have superior representations for sequences of like things (for example, strings). In simple cases like this, we would represent the sequence of strings as a std::vector<std::string>. However, C++ does not provide you with the command line arguments in this form, but instead in the same form that C gave them to you (along with a count of how many strings there are - with std::vector, that information would be tracked by the vector).

Every parameter you provide on the command line will thus be a string. There is no type-checking done by the command line. It cannot ensure that you type '512' for the width rather than 'fivehundredandtwelve'. The only type that can adequately represent any given parameter is a string type, so that's what you get.

Therefore, if you are expecting an integral type, you must do the conversion yourself. If you are expecting a string, then just use the string; but in C++, save yourself headaches by wrapping it up in a real std::string object at the first opportunity.

ApochPiQ et. al. have already told you what you need to know in order to do the conversion.

Share this post


Link to post
Share on other sites
Quote:
Original post by Zahlman
... I think you don't understand what it means for a variable to be of the type char, based on how you are writing.

In C++, we have a superior representation for strings, called std::string. We also have superior representations for sequences of like things (for example, strings). In simple cases like this, we would represent the sequence of strings as a std::vector<std::string>. However, C++ does not provide you with the command line arguments in this form, but instead in the same form that C gave them to you (along with a count of how many strings there are - with std::vector, that information would be tracked by the vector).

Therefore, if you are expecting an integral type, you must do the conversion yourself. If you are expecting a string, then just use the string; but in C++, save yourself headaches by wrapping it up in a real std::string object at the first opportunity.



Incidentally, because of the way C++ containers work and implicit constructors work, the conversion you speak of is actually trivial. One of the constructors to std::vector<T> takes in a begin and end iterator of another sequence in order to copy from. Also, pointers are iterators, and there is an implicit constructor from char* to string, therefore, you can do this:



int main(int argc,char** argv)
{
std::vector<std::string> args(argv,argv + argc);
std::cout << "The name of this program is " << args[0] << std::endl;
return 0;
}




A lot of people will probably go "whah?" at that, but the basic idea is as follows: you can construct a std::string from a char*, so an iterator to a char* can be used to construct a vector of strings. A pointer is an iterator, so a char** is really an iterator of char*, each of which constructs a string in the vector, which takes a begin and end iterator as arguments. Since the beginning of the list is argv, then the iterator to one past the end of the list is &argv[argc], but since that is cryptic, we simply write it as argv + argc.

Share this post


Link to post
Share on other sites
Yes. I didn't bother with that because the OP apparently is expecting a specific number of arguments of specific types in a specific order. :)

OP:

What?

Quote:
ApochPiQ et. al. have already told you what you need to know in order to do the conversion.


Nobody mentioned atoi(). So why are you thanking them, and then ignoring what they said to use an inferior method that you researched yourself?

Share this post


Link to post
Share on other sites
Hi,
Quote:
Nobody mentioned atoi(). So why are you thanking them, and then ignoring what they said to use an inferior method that you researched yourself?
Because they taught me that argv an array of char arrays. Which I didn't know. And that furthermore, to convert "512" to 512, I simply had to parse the char array. As I said, I've never written this kind of code before, so it was actually the rudimentary outline I picked up from the posts that was really what was most helpful. Plus, it's polite to thank you guys for your time in answering me. Would you rather I not?

And BTW, atoi(...) works just fine for this. I can't imagine why it would be inferior, except in terms of flexibility, which, for my purposes, I don't really care about. I'm expecting a value > 0, so if it returns 0 because the user passed something else, I can handle that. And the whole program takes less than one second to run and is single-threaded, so I don't care about it being thread-safe or async-safe. And if there were any other problems, I wouldn't care either, because it's fairly non-important code. Not to mention, the whole thing looks cleaner, and moreover uses a well-tested library function that exists for just this purpose.

-G

Share this post


Link to post
Share on other sites

This topic is 2655 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this