Access command line arguments without using char *

2019-01-28 04:28发布

问题:

Is there any way to access the command line arguments, without using the argument to main? I need to access it in another function, and I would prefer not passing it in.

I need a solution that only necessarily works on Mac OS and Linux with GCC.

回答1:

I do not think you should do it as the C runtime will prepare the arguments and pass it into the main via int argc, char **argv, do not attempt to manipulate the behaviour by hacking it up as it would largely be unportable or possibly undefined behaviour!! Stick to the rules and you will have portability...no other way of doing it other than breaking it...



回答2:

I don't know how to do it on MacOS, but I suspect the trick I will describe here can be ported to MacOS with a bit of cross-reading.

On linux you can use the so called ".init_array" section of the ELF binary, to register a function which gets called during program initilization (before main() is called). This function has the same signature as the normal main() function, execept it returns "void". Thus, you can use this function to remember or process argc, argv[] and evp[].

Here is some code you can use:

static void my_cool_main(int argc, char* argv[], char* envp[])
{
    // your code goes here
}

__attribute__((section(".init_array"))) void (* p_my_cool_main)(int,char*[],char*[]) = &my_cool_main;

PS: This code can also be put in a library, so it should fit your case. It even works, when your prgram is run with valgrind - valgrind does not fork a new process, and this results in /proc/self/cmdline showing the original valgrind command-line.

PPS: Keep in mind that during this very early program execution many subsystem are not yet fully initialized - I tried libc I/O routines, they seem to work, but don't rely on it - even gloval variables might not yet be constructed, etc...



回答3:

You can copy them into global variables if you want.



回答4:

You can. Most platforms provide global variables __argc and __argv. But again, I support zneak's comment.

P.S. Use boost::program_options to parse them. Please do not do it any other way in C++.



回答5:

In Linux, you can open /proc/self/cmdline (assuming that /proc is present) and parse manually (this is only required if you need argc/argv before main() - e.g. in a global constructor - as otherwise it's better to pass them via global vars).

More solutions are available here: http://blog.linuxgamepublishing.com/2009/10/12/argv-and-argc-and-just-how-to-get-them/

Yeah, it's gross and unportable, but if you are solving practical problems you may not care.



回答6:

Is there some reason why passing a pointer to space that is already consumed is so bad? You won't be getting any real savings out of eliminating the argument to the function in question and you could set off an interesting display of fireworks. Skirting around main()'s call stack with creative hackery usually ends up in undefined behavior, or reliance on compiler specific behavior. Both are bad for functionality and portability respectively.

Keep in mind the arguments in question are pointers to arguments, they are going to consume space no matter what you do. The convenience of an index of them is as cheap as sizeof(int), I don't see any reason not to use it.

It sounds like you are optimizing rather aggressively and prematurely, or you are stuck with having to add features into code that you really don't want to mess with. In either case, doing things conventionally will save both time and trouble.