5

Is it possible to get the command line arguments without receiving them via int main(int, char**)? I don't want to pass the arguments to multiple methods, so a global function would be perfect. Also, I do not want to store the arguments by myself via global variables. I'm running Windows and Linux.

edit: Example:

int main()
{
   int argc = GetArgumentCount();
   char ** argv = GetArguments();
   return 0;
}

edit: It's possible to use LPTSTR WINAPI GetCommandLine(void); in win32.

https://msdn.microsoft.com/en-us/library/ms683156(v=vs.85).aspx

I'm looking for equivalent functions in Linux.

grimgrom
  • 730
  • 1
  • 9
  • 18
  • 4
    It's not necessary to use global variables when reading command line, it's a matter of architecture of the program. – Jepessen Nov 17 '17 at 17:04
  • 3
    Why would you want to do this? What's wrong with getting them via `int main(int, char**)`? Can you give us any good reason for not retrieving them from the arguments passed to `main`? – Jabberwocky Nov 17 '17 at 17:09
  • 2
    Very unclear question, because it is lacking motivation. – Basile Starynkevitch Nov 17 '17 at 18:06
  • 1
    Why would a global function be perfect but variables are not? As others have said, this design seems bad. – Matt Nov 17 '17 at 18:27
  • @grimgrom: please **edit your question** to improve it and *add motivation and context*. In general, what you are asking for is crazy. – Basile Starynkevitch Nov 17 '17 at 18:32
  • @BasileStarynkevitch A lack of motivation does not make a question unclear. It is very clear what the OP wants. Motivation != Clarity. – Kröw Mar 26 '23 at 06:19

3 Answers3

7

Is it possible to get the command line arguments without receiving them via int main(int, char**)?

Yes, with platform-specific functions. But that's not necessary (see below).

I don't want to pass the arguments to multiple methods,

That's understandable. It's an anti-pattern also known as "tramp data".

Also, I do not want to store the arguments by myself via global variables.

Yes, global variables are rarely a good idea.

Here's an alternative approach: store them as a static local container object in some globally available non-member function which returns the container by reference.

Example:

#include <iostream>
#include <string>
#include <vector>

std::vector<std::string>& Arguments()
{
    static std::vector<std::string> arguments;
    return arguments;
}

void f()
{
    // use arguments anywhere else:
    std::cout << Arguments()[0];
}

int main(int argc, char* argv[])
{
    for (int i = 0; i < argc; ++i)
    {
        Arguments().push_back(argv[i]);
    }

    f();
}

Of course, this can be made more sophisticated. For example, you might want to prevent anyone else but main from changing the vector by wrapping the vector in a class and declaring main as a friend, something like this:

#include <iostream>
#include <string>
#include <vector>

class Arguments final
{
public:
    static int Count()
    {
        return arguments.size();
    }

    static std::string Get(int index)
    {
        return arguments[index];
    };

private:
    Arguments() = delete;
    friend int main(int argc, char* argv[]);
    static std::vector<std::string> arguments;
};

std::vector<std::string> Arguments::arguments;

void f()
{
    // use Arguments anywhere else:
    std::cout << Arguments::Get(0);
}

int main(int argc, char* argv[])
{
    for (int i = 0; i < argc; ++i)
    {
        Arguments::arguments.push_back(argv[i]);
    }

    f();
}

Note that special care is needed to avoid bugs at program shutdown, when static objects are destroyed. You must make sure that no destructor of a static object accesses Arguments, or else you risk undefined behaviour.

Christian Hackl
  • 27,051
  • 3
  • 32
  • 62
  • It's a shame that it doesn't seem immediately apparent that C++ has a proper way for handling this in 2017. I mean it seems like each example is primitive and reinvents that primitive wheel; Especially coming from python where getarg is so simple and nice. – LUser Nov 05 '21 at 14:05
2

Is it possible to get the command line arguments without receiving them via int main(int, char**) ?

No (at least, not in portable manner), however you could put the usual argc, argv into some global variable (or other global data, often after parsing). And that could also be into some static data with other functions in the same translation unit retrieving it. Hence a reasonable (readable and portable) approach would be:

static int myargc;
static char **myargv;
int GetArgumentCount(void) {
  return myargc;
}
char**GetArguments(void) {
  return myargv;
}
int main(int argc, char**argv) {
   myargc= argc;
   myargv= argv;
   /// etc....

Notice that on some systems or some implementations you might access to the command line arguments in some other ways.

dirty Linux specific tricks

For example, on Linux, using proc(5), you might parse /proc/self/cmdline but it is unreasonable to do that (on your Linux system, try to run od -cx /proc/self/cmdline in your terminal to guess what I mean), so I still recommend using int main(int argc, char**argv) and storing, in some global or static data, the argc and argv, or more probably, do some parsing of program arguments.

So on Linux, you might code your GetArgumentCount and GetArguments functions (by parsing /proc/self/cmdline, see also this) but it would be foolish to do so without using argc and argv from main (even if it is technically doable). Coding such a crazy GetArgumentCount and GetArguments which parses /proc/self/cmdline is left as an exercise to the masochistic reader.

Perhaps you need that because some static data's constructor -running before main and called before it from crt0- uses them; but in that case, your program's design is IMHO very wrong. I have no idea if similar dirty tricks are doable in Windows.

Basile Starynkevitch
  • 223,805
  • 18
  • 296
  • 547
  • "Also, I do not want to store the arguments by myself via global variables." – grimgrom Nov 17 '17 at 17:16
  • Technically, claiming that it's outright impossible is wrong. It might be more _portable_ to collect argc/argv, but if `ps` (or the task manager or some os equivalent) can show you your command line arguments, surely you can get them the same way `ps` (or task manager or os equivalent) does. – H Walters Nov 17 '17 at 17:41
  • @HWalters; thanks for your comment, which inspired me a better answer. But my answer above is as wicked as [this](https://stackoverflow.com/a/47122805/841108) one (which got downvoted). – Basile Starynkevitch Nov 17 '17 at 18:30
  • On Windows, you can use [`GetCommandLineW()`](https://msdn.microsoft.com/en-us/library/windows/desktop/ms683156.aspx) and [`CommandLineToArgvW()`](https://msdn.microsoft.com/en-us/library/windows/desktop/bb776391.aspx) – Remy Lebeau Nov 17 '17 at 20:11
1

If you really think that is a good idea, you can easily make cor command line arguments global:

int argc_ = 0;
char** argv_ = NULL;

int main(int argc, char* argv[]) {
    argc_ = argc;
    argv_ = argv;

    // ...
}
user0042
  • 7,917
  • 3
  • 24
  • 39