Alternative way to obtain argc and argv of a process
Solution 1
On Linux, you can get this information from the process's proc file system, namely /proc/$$/cmdline
:
int pid = getpid();
char fname[PATH_MAX];
char cmdline[ARG_MAX];
snprintf(fname, sizeof fname, "/proc/%d/cmdline", pid);
FILE *fp = fopen(fname);
fgets(cmdline, sizeof cmdline, fp);
// the arguments are in cmdline
Solution 2
The arguments to main
are defined by the C runtime, and the only standard/portable way to obtain the command line arguments. Don't fight the system. :)
If all you want to do is to provide access to command line parameters in other parts of the program with your own API, there are many ways to do so. Just initialise your custom class using argv/argc
in main
and from that point onward you can ignore them and use your own API. The singleton pattern is great for this sort of thing.
To illustrate, one of the most popular C++ frameworks, Qt uses this mechanism:
int main(int argc, char* argv[])
{
QCoreApplication app(argc, argv);
std::cout << app.arguments().at(0) << std::endl;
return app.exec();
}
The arguments are captured by the app and copied into a QStringList
. See QCoreApplication::arguments() for more details.
Similarly, Cocoa on the Mac has a special function which captures the command line arguments and makes them available to the framework:
#import <Cocoa/Cocoa.h>
int main(int argc, char *argv[])
{
return NSApplicationMain(argc, (const char **)argv);
}
The arguments are then available anywhere in the app using the NSProcessInfo.arguments property.
I notice in your updated question that your class directly stores a copy of argc/argv
verbatim in its instance:
int const argc_;
char const** const argv_;
While this should be safe (the lifetime of the argv
pointers should be valid for the full lifetime of the process), it is not very C++-like. Consider creating a vector of strings (std::vector<std::string>
) as a container and copy the strings in. Then they can even be safely mutable (if you want!).
I want to make a class that is independent of main() so that argc and argv don't have to be passed explicitly to the code that uses them.
It is not clear why passing this info from main
is somehow a bad thing that is to be avoided. This is just how the major frameworks do it.
I suggest you look at using a singleton to ensure there is only one instance of your Application
class. The arguments can be passed in via main
but no other code need know or care that this is where they came from.
And if you really want to hide the fact that main
's arguments are being passed to your Application
constructor, you can hide them with a macro.
Solution 3
To answer the question in part, concerning Windows, the command line can be obtained as the return of the GetCommandLine
function, which is documented here, without explicit access to the arguments of the main
function.
Solution 4
I totally agree with @gavinb and others. You really should use the arguments from main
and store them or pass them where you need them. That's the only portable way.
However, for educational purposes only, the following works for me with clang
on OS X and gcc
on Linux:
#include <stdio.h>
__attribute__((constructor)) void stuff(int argc, char **argv)
{
for (int i=0; i<argc; i++) {
printf("%s: argv[%d] = '%s'\n", __FUNCTION__, i, argv[i]);
}
}
int main(int argc, char **argv)
{
for (int i=0; i<argc; i++) {
printf("%s: argv[%d] = '%s'\n", __FUNCTION__, i, argv[i]);
}
return 0;
}
which will output:
$ gcc -std=c99 -o test test.c && ./test this will also get you the arguments
stuff: argv[0] = './test'
stuff: argv[1] = 'this'
stuff: argv[2] = 'will'
stuff: argv[3] = 'also'
stuff: argv[4] = 'get'
stuff: argv[5] = 'you'
stuff: argv[6] = 'the'
stuff: argv[7] = 'arguments'
main: argv[0] = './test'
main: argv[1] = 'this'
main: argv[2] = 'will'
main: argv[3] = 'also'
main: argv[4] = 'get'
main: argv[5] = 'you'
main: argv[6] = 'the'
main: argv[7] = 'arguments'
The reason is because the stuff
function is marked as __attribute__((constructor))
which will run it when the current library is loaded by the dynamic linker. That means in the main program it will run even before main
and have a similar environment. Therefore, you're able to get the arguments.
But let me repeat: This is for educational purposes only and shouldn't be used in any production code. It won't be portable and might break at any point in time without warning.
Solution 5
In Windows, if you need to get the arguments as wchar_t *
, you can use CommandLineToArgvW()
:
int main()
{
LPWSTR *sz_arglist;
int n_args;
int result;
sz_arglist = CommandLineToArgvW(GetCommandLineW(), &n_args);
if (sz_arglist == NULL)
{
fprintf(stderr, _("CommandLineToArgvW() failed.\n"));
return 1;
}
else
{
result = wmain(n_args, sz_arglist);
}
LocalFree(sz_arglist);
return result;
}
This is very convenient when using MinGW because gcc
does not recognize int _wmain(int, wchar_t *)
as a valid main
prototype.
Related videos on Youtube
user1095108
Updated on June 14, 2022Comments
-
user1095108 almost 2 years
I'm looking for alternative ways to obtain the command line parameters
argc
andargv
provided to a process without having direct access to the variables passed intomain()
.I want to make a class that is independent of
main()
so thatargc
andargv
don't have to be passed explicitly to the code that uses them.EDIT: Some clarification seems to be in order. I have this class.
class Application { int const argc_; char const** const argv_; public: explicit Application(int, char const*[]); }; Application::Application(int const argc, char const* argv[]) : argc_(argc), argv_(argv) { }
But I'd like a default constructor
Application::Application()
, with some (most probably) C code, that pullsargc
andargv
from somewhere.-
user3078414 about 8 yearsWhat do you mean with "obtain"? Where else from?
-
Some programmer dude about 8 yearsThere's no portable or standard way of getting arguments to the program except the arguments to
main
. -
user1095108 about 8 years@PaulR yes, yes, the APIs are in C, as you know, but class is in C++. I didn't want an answer featuring python, even though it would be cool.
-
user1095108 about 8 years@JoachimPileborg True, but the question is OS-specific, non-portable.
-
Some programmer dude about 8 yearsAs for the user not needing to pass
argc
andargv
to the "class", take a look at just about all portable and platform-independent GUI frameworks, they all needs the user of the framework to passargc
andargv
to the framework explicitly. So it's common and not something programmers are unused to. -
Some programmer dude about 8 yearsYou tag this question
linux
,windows
,posix
andbsd
and say this question is OS-specific? If it was OS-specific you would mention only one OS, the one you target. -
user1095108 about 8 years@JoachimPileborg The frameworks contain OS-specific code, not just portable code, there is not reason whatsoever why not make the command line gathering part OS-specific too. I'm trying to gather as many ways to gather the command line as possible, but not infinite and not opinion-based.
-
CoffeDeveloper about 8 yearschicken-egg problem, if you want a code that provides argument, then that code have to rely on main, directly or indirectly you will have a main.
-
CoffeDeveloper about 8 yearsWe should stop upvoting ill-formed questions before getting the question right. The question is still not clear to me, you basically want to get those parameters, without the need to pass them? You can create a wrapper that if injected provides parameters indirectly. I just think that once requirements of OP are clear, then we can just proof if what he's want is even possible
-
-
Admin about 8 years1. you can read /proc/self/cmdline 2. args could have been destroyed 3. it is super odd to deal with /proc files with FILE abstraction 4. ARG_MAX is only a limit for one argument, not all args in total 5. missing error checks, arguably could be omitted in the example. However, the biggest issue is that OP is likely trying to do something wrong and such answer like this should not be posted in the first place without further clarification.
-
Cory Klein about 8 yearsThis is a popular answer. You may consider adding an example in-line of how to use
GetCommandLine
. -
user1095108 about 8 yearsThat's exactly what I don't want to do.
-
CoffeDeveloper about 8 yearsSo you want a getter for a global variable, but you don't want the global variable eh?
-
jamesqf about 8 yearsBut the OP states that this is in C, so there are no classes. You could pass them to an init function, and have the values stored in static variables in the module code.
-
Luaan about 8 years@jamesqf Well, I'm just using the same name the OP used :) Passing the values is the important part, not how exactly it is implemented.
-
sfdcfox about 8 yearsClasses in C? Say it ain't so!
-
isanae about 8 yearsOr just with __argc, __argv and __wargv.
-
T.E.D. about 8 yearsUpvoting this. The typical method I see used for API's that want CL access to parse their own arguments (eg: QT) is to just ask for argv and argc. The nice thing about using the standard idiom is that experienced programmers will know what you are doing at a glance.
-
Noah Spurrier about 8 yearsI believe that /proc/*/cmdline is truncated to some max length constant. This is not a limitation of the size of the process command-line that the OS can start. Instead, this is a limitation of the process list record keeping in Linux. So you can start a process with a longer list of arguments, but the kernel is not going to remember them all for the purpose of trying to read arguments from the process list.
-
Admin about 8 yearsThe kernel does not memorize arguments. Instead it stores addresses for both start and end of said args and then reads them from target process address space. I don't see any code truncating the result either (unless the requested amount is too small of course). lxr.free-electrons.com/source/fs/proc/base.c#L199
-
Patrick Collins about 8 yearsThat's pretty nifty. Are
__attribute__((constructor))
functions guaranteed to have access to argv/argc, or does this just abuse some accident of the representation? -
Matthieu M. about 8 yearsI understand the idea of using a global (it's ugly, but it does the job done), however WHY enforcing uniqueness? What's wrong with allowing anyone to create a fake set of arguments and pass those instead?
-
Johannes Weiss about 8 yearsIt's not guaranteed at all.
-
user1095108 about 8 yearsIt's exactly what I don't want. It may be wrong to find
argc
andargv
using alternative means, but why should people be discouraged from doing so anyway? There are situations apart from the one I described, where it seems to be useful to be able to do so. -
gavinb about 8 years@MatthieuM. The singleton is merely to preserve the same semantics as the data it encapsulates; there is one set of read-only arguments. Not a strong requirement.
-
T.E.D. about 8 yearsFrom a strategic point of view, many SE users consider any singleton use to be code smell, and will downvote an otherwise good answer just for mentioning them. As someone who upvoted this answer, I think that would be a shame. If its not central to your answer, no point in suggesting something controversial.
-
gavinb about 8 years@user1095108 You say that you don't want to get access the arguments the standard way, but not why. Accessing the arguments from another part of the application is possible, regardless of how they are obtained in the first place. If you don't want to use the defined mechanism, you would need to circumvent the C runtime startup code, which opens a whole can of worms.
-
saagarjha about 6 years@gavinb Interestingly, on macOS,
NSApplicationMain
actually ignores the passed inargc
andargv
and gets it directly from_NSGetArgc
and_NSGetArgv
. -
gavinb about 6 years@SaagarJha Interesting, yes I just looked up the implantation in opensource.apple.com/source/Libc/Libc-763.13/sys/… . It relies on very specific and detailed knowledge of
dyld
andlibSystem
internals. -
Evgen about 5 yearsTrying to use this, but only getting the command name (with path, if was explicitly specified). So
cat /proc/self/cmdline x y z
returnscat/proc/self/cmdlinexyz
, butfgets
on that file returns justcat
. Why is that? -
Evgen about 5 years(answering myself) - Turns out the args are NULL-separated. Can't just use a string :(
-
saagarjha over 4 yearsglibc and dyld implement this extension; musl does not. Take of that what you will.
-
Sergey Kalinichenko over 2 yearsThis is such a hack... Such an amazingly beautiful, delightful hack!