获取进程的argc和argv的替代方法

use*_*108 21 c++ linux windows bsd posix

我正在寻找替代方法来获取命令行参数argcargv提供给进程,而无需直接访问传入的变量main().

我想使一类是独立的main(),这样argcargv没有明确地传递给使用它们的代码.

编辑:有些澄清似乎是有序的.我有这门课.

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代码,拉动argcargv从某处.

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)

  • 1.你可以阅读/ proc/self/cmdline 2. args可能已被破坏3.使用FILE抽象处理/ proc文件是非常奇怪的4. ARG_MAX只是一个参数的限制,而不是所有args的总数5缺少错误检查,可以说在示例中可以省略.然而,最大的问题是OP可能会尝试做错事,如果没有进一步澄清,这样的答案不应该首先发布. (7认同)
  • 我相信/ proc / * / cmdline被截断为一些最大长度常量。这不是操作系统可以启动的进程命令行大小的限制。相反,这是Linux中保留进程列表记录的限制。因此,您可以使用更长的参数列表启动进程,但是内核不会为了尝试从进程列表中读取参数而将所有参数都记住。 (2认同)

gav*_*inb 29

参数main由C运行时定义,是获取命令行参数的唯一标准/可移植方式.不要打架系统.:)

如果您只想使用自己的API提供对程序其他部分中命令行参数的访问,则有很多方法可以执行此操作.只需使用argv/argcin 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构造函数的事实,你可以用宏来隐藏它们.


Cod*_*dor 15

要回答有关Windows的部分问题,可以获取命令行作为GetCommandLine函数的返回(此处记录),而无需显式访问main函数的参数.

  • 这是一个受欢迎的答案.您可以考虑添加一个如何使用`GetCommandLine`的示例. (6认同)
  • 或者只是使用 [__argc、__argv 和 __wargv](https://msdn.microsoft.com/en-us/library/dn727674.aspx)。 (2认同)

Joh*_*iss 13

我完全赞同@gavinb和其他人.你真的应该使用来自的参数main并存储它们或在你需要的地方传递它们.这是唯一可移植的方式.

但是,仅出于教育目的,以下适用clang于OS X和gccLinux:

#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并具有类似的环境.因此,您可以获得参数.

但请允许我重复一遍:这仅用于教育目的,不应在任何生产代码中使用.它不会是便携式的,可能会在没有任何警告的情况下随时中断.

  • 那是呃,可怕的. (4认同)
  • 那太漂亮了.`__attribute __((constructor))`函数是否保证可以访问argv/argc,或者这只是滥用了表示的一些意外? (4认同)

jda*_*nay 5

在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原型.


Lua*_*aan 5

传递值不构成创建依赖关系.你的班级并不关心这些argcargv价值观的来源 - 它只是希望它们通过.您可能希望在某处复制值 - 不能保证它们不会被更改(这同样适用于替代方法GetCommandLine).

事实恰恰相反 - 当你使用类似的东西时,你正在创建一个隐藏的依赖GetCommandLine.突然间,你没有一个简单的"传递价值"语义,而是"神奇地从其他地方接受他们的输入" - 结合前面提到的"价值随时可能发生变化",这使你的代码变得更加脆弱,更不用说了无法测试.解析命令行参数绝对是自动化测试非常有益的情况之一.如果你愿意,它是一个全局变量而不是方法论证方法.