use*_*108 21 c++ linux windows bsd posix
我正在寻找替代方法来获取命令行参数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)
{
}
Run Code Online (Sandbox Code Playgroud)
但我想一个默认的构造Application::Application()
,有一些(最有可能)的C代码,拉动argc
和argv
从某处.
flu*_*ter 32
在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
Run Code Online (Sandbox Code Playgroud)
gav*_*inb 29
参数main
由C运行时定义,是获取命令行参数的唯一标准/可移植方式.不要打架系统.:)
如果您只想使用自己的API提供对程序其他部分中命令行参数的访问,则有很多方法可以执行此操作.只需使用argv/argc
in main
以及之后的初始化自定义类,您可以忽略它们并使用您自己的API.单身模式非常适合这种事情.
为了说明最流行的C++框架之一,Qt使用了这种机制:
int main(int argc, char* argv[])
{
QCoreApplication app(argc, argv);
std::cout << app.arguments().at(0) << std::endl;
return app.exec();
}
Run Code Online (Sandbox Code Playgroud)
这些参数由应用程序捕获并复制到一个QStringList
.有关更多详细信息,请参阅QCoreApplication :: arguments().
类似地,Mac上的Cocoa有一个特殊的函数,它捕获命令行参数并使它们可用于框架:
#import <Cocoa/Cocoa.h>
int main(int argc, char *argv[])
{
return NSApplicationMain(argc, (const char **)argv);
}
Run Code Online (Sandbox Code Playgroud)
然后,使用NSProcessInfo.arguments属性在应用程序的任何位置都可以使用这些参数.
我在你的更新问题中注意到你的类直接argc/argv
在其实例中存储了一个逐字的副本:
int const argc_;
char const** const argv_;
Run Code Online (Sandbox Code Playgroud)
虽然这应该是安全的(argv
指针的生命周期应该在进程的整个生命周期内有效),但它不是很像C++.考虑创建一个strings(std::vector<std::string>
)向量作为容器并复制字符串.然后它们甚至可以安全地变更(如果你想!).
我想创建一个独立于main()的类,这样就不必将argc和argv显式传递给使用它们的代码.
目前尚不清楚为什么传递这些信息在main
某种程度上是一件应该避免的坏事.这就是主要框架如何做到这一点.
我建议你看看使用单例来确保你的Application
类只有一个实例.参数可以通过via传递,main
但没有其他代码需要知道或关心它们来自哪里.
如果你真的想隐藏将main
参数传递给你的Application
构造函数的事实,你可以用宏来隐藏它们.
Joh*_*iss 13
我完全赞同@gavinb和其他人.你真的应该使用来自的参数main
并存储它们或在你需要的地方传递它们.这是唯一可移植的方式.
但是,仅出于教育目的,以下适用clang
于OS X和gcc
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;
}
Run Code Online (Sandbox Code Playgroud)
这将输出:
$ 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'
Run Code Online (Sandbox Code Playgroud)
原因是因为该stuff
函数被标记为__attribute__((constructor))
在动态链接器加载当前库时将运行该函数.这意味着在主程序中它甚至会在之前运行main
并具有类似的环境.因此,您可以获得参数.
但请允许我重复一遍:这仅用于教育目的,不应在任何生产代码中使用.它不会是便携式的,可能会在没有任何警告的情况下随时中断.
在Windows中,如果需要获取参数wchar_t *
,可以使用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;
}
Run Code Online (Sandbox Code Playgroud)
这在使用MinGW时非常方便,因为gcc
它不能识别int _wmain(int, wchar_t *)
为有效的main
原型.
传递值不构成创建依赖关系.你的班级并不关心这些argc
或argv
价值观的来源 - 它只是希望它们通过.您可能希望在某处复制值 - 不能保证它们不会被更改(这同样适用于替代方法GetCommandLine
).
事实恰恰相反 - 当你使用类似的东西时,你正在创建一个隐藏的依赖GetCommandLine
.突然间,你没有一个简单的"传递价值"语义,而是"神奇地从其他地方接受他们的输入" - 结合前面提到的"价值随时可能发生变化",这使你的代码变得更加脆弱,更不用说了无法测试.解析命令行参数绝对是自动化测试非常有益的情况之一.如果你愿意,它是一个全局变量而不是方法论证方法.