C++ 获取进程的argc和argv的替代方法
我正在寻找其他方法来获取提供给进程的命令行参数C++ 获取进程的argc和argv的替代方法,c++,linux,windows,posix,bsd,C++,Linux,Windows,Posix,Bsd,我正在寻找其他方法来获取提供给进程的命令行参数argc和argv,而无需直接访问传递到main()的变量 我想创建一个独立于main()的类,这样argc和argv就不必显式地传递给使用它们的代码 编辑:一些澄清似乎是正确的。我有这门课 class Application { int const argc_; char const** const argv_; public: explicit Application(int, char const*[]); }; Applica
argc
和argv
,而无需直接访问传递到main()
的变量
我想创建一个独立于main()
的类,这样argc
和argv
就不必显式地传递给使用它们的代码
编辑:一些澄清似乎是正确的。我有这门课
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)
{
}
但是我想要一个默认构造函数
Application::Application()
,带有一些(很可能)C代码,从某处提取argc
和argv
。要部分回答关于Windows的问题,可以通过返回GetCommandLine
函数来获取命令行,它是有文档记录的,没有显式访问main
函数的参数。到main
的参数是由C运行时定义的,也是获取命令行参数的唯一标准/可移植方法。不要与体制对抗。:)
如果您只想使用自己的API在程序的其他部分提供对命令行参数的访问,那么有很多方法可以做到这一点。只需在main
中使用argv/argc
初始化自定义类,从那时起,您可以忽略它们并使用自己的API。单例模式非常适合这种情况
说明,最流行的C++框架之一,Qt使用这种机制:
int main(int argc, char* argv[])
{
QCoreApplication app(argc, argv);
std::cout << app.arguments().at(0) << std::endl;
return app.exec();
}
然后,使用属性的应用程序中的任何位置都可以使用参数
我注意到在您更新的问题中,您的类在其实例中直接存储了argc/argv
的副本:
int const argc_;
char const** const argv_;
虽然这应该是安全的(argvargv
指针的生命周期应该在进程的整个生命周期内都是有效的),但它不是很像C++。考虑创建一个字符串向量(<代码> STD::vector < /代码>)作为容器并复制字符串。然后,它们甚至可以安全地可变(如果您愿意的话!)
我想创建一个独立于main()的类,这样就不必显式地将argc和argv传递给使用它们的代码
不清楚为什么从main
传递此信息是一件必须避免的坏事。主要框架就是这样做的
我建议您考虑使用单例来确保应用程序
类只有一个实例。这些参数可以通过main
传入,但其他代码不需要知道或关心它们的来源
如果你真的想隐藏
main
的参数正在传递给你的应用程序构造函数的事实,你可以用一个宏来隐藏它们。在Linux上,你可以从进程的proc文件系统,即/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
对于需要int-argc,char*argv[]
类型参数的函数,我知道很少有常见的场景。一个明显的例子是GLUT,它的初始化函数从main()
接收这些参数,这是一种“嵌套的main”场景。这可能是你想要的行为,也可能不是。如果没有,因为没有命名这些参数的约定,只要您的函数有参数解析器,并且您知道自己在做什么,就可以根据需要执行任何操作,硬编码:
int foo = 1;
char * bar[1] = {" "};
或从用户输入读取或以其他方式生成,AFAIK
int myFunc( int foo, char *bar[]){
//argument parser
{… …}
return 0;
}
请看这个。在Windows中,如果需要以wchar\u t*
的形式获取参数,可以使用命令行toargvw()
:
这在使用MinGW时非常方便,因为gcc
不会将int\u wmain(int,wchar\u t*)
识别为有效的main
原型。传递值并不构成创建依赖关系。您的类不关心那些argc
或argv
值从何而来-它只希望传递它们。但是,您可能希望将这些值复制到某个地方—不能保证它们不会被更改(这同样适用于替代方法,如GetCommandLine
)
事实上,恰恰相反——当您使用类似于GetCommandLine
的东西时,您正在创建一个隐藏的依赖项。突然之间,您不再使用简单的“传递值”语义,而是“神奇地从其他地方获取它们的输入”——再加上前面提到的“值可以随时更改”,这使得您的代码更加脆弱,更不用说无法测试了。解析命令行参数无疑是自动化测试非常有益的情况之一。这是一个全局变量,而不是一个方法参数方法,如果你愿意的话。听起来你想要的是一个全局变量;您应该做的就是将argc和argv作为参数传递。我完全同意@gavinb和其他人的观点。您确实应该使用main
中的参数,并将它们存储或传递到需要它们的地方。这是唯一的便携方式
但是,仅出于教育目的,以下内容适用于我在OS X上使用clang
、在Linux上使用gcc
:
#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;
}
原因是stuff
函数被标记为\uuuuu属性((构造函数))
,它将在动态链接器加载当前库时运行。这意味着在主程序中,它将在main
之前运行,并且具有类似的环境。因此,您可以获得参数
但让我重复一遍:这只是出于教育目的,不应该在任何生产代码中使用。它不可移植,可能会在没有警告的情况下在任何时间点损坏。在C/C++中,如果main()
没有导出它们,那么就没有直接的方法来访问它们;然而,这并不意味着没有间接的方法。许多类似Posix的系统使用elf格式,该格式通过
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;
}
#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;
}
$ 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'