是否可以更改 argv 或者我需要创建它的调整副本?

发布于 2024-07-23 14:26:36 字数 97 浏览 14 评论 0原文

我的应用程序可能会传入大量参数,我想避免命中内存将参数复制到过滤列表中。 我想就地过滤它们,但我很确定弄乱 argv 数组本身或它指向的任何数据可能是不可取的。 有什么建议么?

My application has potentially a huge number of arguments passed in and I want to avoid the memory of hit duplicating the arguments into a filtered list. I would like to filter them in place but I am pretty sure that messing with argv array itself, or any of the data it points to, is probably not advisable. Any suggestions?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

不喜欢何必死缠烂打 2024-07-30 14:26:37

argv 的原始分配保留为编译器/运行时选择。
因此随意修改它可能并不安全。 许多系统将其构建在堆栈上,因此当 main 返回时它会自动释放。 其他的将其构建在堆上,并在 main 返回时释放(或不释放)它。

更改参数的值是安全的,只要您不尝试使其更长(缓冲区溢出错误)。 打乱参数的顺序是安全的。

删除您已经预处理的参数,类似这样的操作将起作用:(

未检查许多错误条件,“--special”其他未检查的第一个参数,等等。毕竟,这只是一个概念演示。)

int main(int argc, char** argv)
{
    bool doSpecial = false; // an assumption
    if (0 == strcmp(argv[1], "--special"))
    {
        doSpecial = true; // no longer an assumption
        // remove the "--special" argument
        //  but do copy the NULL at the end.
        for(int i=1; i<argc; ++i)
            argv[i]  = argv[i+1];
        --argc;
    }
    // all normal processing with "--special" removed.
    // the doSpecial flag is available if wanted.
    return 0;
}

但请参阅此以了解完整操作:(libiberty 库中用于操作 argv 样式向量的部分)

http://www.opensource.apple.com/source/gcc/ gcc-5666.3/libiberty/argv.c

它已获得 GNU LGPL 许可。

The original allocation of argv is left as a compiler/runtime choice.
So it may not be safe to modify it willy-nilly. Many systems build it on the stack, so it is auto-deallocated when main returns. Other build it on the heap, and free it (or not) when main returns.

It is safe to change the value of an argument, as long as you don't try to make it longer (buffer overrun error). It is safe to shuffle the order of the arguments.

To remove arguments you've preprocessed, something like this will work:

( lots of error conditions not checked for, "--special" other that first arg not checked for, etc. This is, after all, just a demo-of-concept. )

int main(int argc, char** argv)
{
    bool doSpecial = false; // an assumption
    if (0 == strcmp(argv[1], "--special"))
    {
        doSpecial = true; // no longer an assumption
        // remove the "--special" argument
        //  but do copy the NULL at the end.
        for(int i=1; i<argc; ++i)
            argv[i]  = argv[i+1];
        --argc;
    }
    // all normal processing with "--special" removed.
    // the doSpecial flag is available if wanted.
    return 0;
}

But see this for full manipulation: (the part of the libiberty library that is used to manipulates argv style vectors)

http://www.opensource.apple.com/source/gcc/gcc-5666.3/libiberty/argv.c

It is licensed GNU LGPL.

阳光下的泡沫是彩色的 2024-07-30 14:26:36

C 标准的最新草案 (N1256) 指出 main 函数有两种允许的形式:

int main (void);
int main (int argc, char* argv[]);

但关键是“或以其他实现定义的方式”这一条款。 在我看来,这是标准中的一个漏洞,大到足以让半挂车通过。

有些人专门使用 const char * 作为 argv 来禁止更改参数。 如果您的主函数是这样定义的,则不允许您更改 argv[] 指向的字符,如以下程序所示:

pax> cat qq.c
#include <stdio.h>
int main (int c, const char *v[]) {
    *v[1] = 'X';
    printf ("[%s]\n", v[1]);
    return 0;
}

pax> gcc -o qq qq.c
qq.c: In function `main':
qq.c:3: error: assignment of read-only location

但是,如果您删除 const,它工作得很好:

pax> cat qq2.c
#include <stdio.h>
int main (int c, char *v[]) {
    *v[1] = 'X';
    printf ("[%s]\n", v[1]);
    return 0;
}

pax> gcc -o qq2 qq2.c ; ./qq2 Hello
[Xello]

我认为 C++ 也是如此。 当前的草案指出:

All implementations shall allow both of the following definitions of main:
    int main();
    int main(int argc, char* argv[]);

但它并没有明确禁止其他变体,因此您大概也可以接受 C++ 中的 const 版本(事实上,g++ 也接受)。

您唯一需要注意的是尝试增加任何元素的大小。 标准没有规定它们的存储方式,因此扩展一个参数可能(可能会)影响其他参数或其他一些不相关的数据。

The latest draft of the C standard (N1256) states that there are two allowed forms of the main function:

int main (void);
int main (int argc, char* argv[]);

but the crux is the clause "or in some other implementation-defined manner". This seems to me to be a loophole in the standard large enough to drive a semi-trailer through.

Some people specifically use const char * for the argv to disallow changes to the arguments. If your main function is defined that way, you are not permitted to change the characters that argv[] points to, as evidenced by the following program:

pax> cat qq.c
#include <stdio.h>
int main (int c, const char *v[]) {
    *v[1] = 'X';
    printf ("[%s]\n", v[1]);
    return 0;
}

pax> gcc -o qq qq.c
qq.c: In function `main':
qq.c:3: error: assignment of read-only location

However, if you remove the const, it works fine:

pax> cat qq2.c
#include <stdio.h>
int main (int c, char *v[]) {
    *v[1] = 'X';
    printf ("[%s]\n", v[1]);
    return 0;
}

pax> gcc -o qq2 qq2.c ; ./qq2 Hello
[Xello]

I think this is also the case for C++. The current draft states:

All implementations shall allow both of the following definitions of main:
    int main();
    int main(int argc, char* argv[]);

but it doesn't specifically disallow other variants so you could presumably accept a const version in C++ as well (and, in fact, g++ does).

The only thing you need to be careful of is trying to increase the size of any of the elements. The standards do not mandate how they're stored so extending one argument may (probably will) affect others, or some other unrelated data.

墨离汐 2024-07-30 14:26:36

一旦 argv 被传递到 main 方法中,您就可以像任何其他 C 数组一样对待它 - 根据需要更改它,只需注意您正在用它做什么。 除了在代码中显式使用数组的内容之外,数组的内容不会影响程序的返回代码或执行。 我想不出有什么理由不“建议”对它进行特殊对待。

当然,您仍然需要注意意外访问超出 argv 范围的内存。 它可以像普通 C 数组一样访问,但它也像任何其他普通 C 数组一样容易出现访问错误。 (感谢所有在评论和其他回复中指出这一点的人!)

Once argv has been passed into the main method, you can treat it like any other C array - change it in place as you like, just be aware of what you're doing with it. The contents of the array don't have an effect on the return code or execution of the program other than what you explicitly do with it in code. I can't think of any reason it wouldn't "be advisable" to treat it specially.

Of course, you still need to take care about accidentally accessing memory beyond the bounds of argv. The flip side of it being accessible like a normal C array is that it's also prone to access errors just like any other normal C array. (Thanks to all who pointed this out in comments and other responses!)

两相知 2024-07-30 14:26:36

C99 标准对于修改 argv (和 argc)有这样的规定:

参数argc和argv以及argv数组指向的字符串应可由程序修改,并在程序启动和程序终止之间保留其最后存储的值。

The C99 standard says this about modifying argv (and argc):

The parameters argc and argv and the strings pointed to by the argv array shall be modifiable by the program, and retain their last-stored values between program startup and program termination.

心的位置 2024-07-30 14:26:36

操作系统在执行之前将 argv 和 argc 推入应用程序堆栈,您可以像对待任何其他堆栈变量一样对待它们。

The operating system push the argv and argc into the applicaton stack before executing it, and you can treat them like any other stack variables.

农村范ル 2024-07-30 14:26:36

我唯一会说直接操作 argv 是一个想法是当应用程序根据 argv[0] 的内容改变其行为时。

然而,在考虑可移植性的情况下,根据 argv[0] 改变程序的行为本身就是一个非常的主意。

除此之外,您可以像对待任何其他数组一样对待它。 正如 Jonathan 所说,GNU getopt() 非破坏性地排列参数列表,我见过其他 getopt() 实现,它们甚至可以序列化甚至散列参数(当程序接近 ARG_MAX 时很有用)。

只是要小心你的指针算术。

The only time I would say that directly manipulating argv is a bad idea would be when an application changes its behavior depending on the contents of argv[0].

However, changing a program's behavior depending on argv[0] is in itself a very bad idea where portability is a concern.

Other than that, you can treat it just like you would any other array. As Jonathan said, GNU getopt() permutes the argument list non-destructively, I've seen other getopt() implementations that go as far as serializing and even hashing the arguments (useful when a program comes close to ARG_MAX).

Just be careful with your pointer arithmetic.

俏︾媚 2024-07-30 14:26:36

根据经验,诸如 GNU getopt() 之类的函数会排列参数列表而不会引起问题。 正如@Tim 所说,只要你明智地玩,你就可以操作指针数组,甚至单个字符串。 只是不要超出任何隐式数组边界。

Empirically, functions such as GNU getopt() permute the argument list without causing problems. As @Tim says, as long as you play sensibly, you can manipulate the array of pointers, and even individual strings. Just don't overrun any of the implicit array boundaries.

何止钟意 2024-07-30 14:26:36

有些图书馆就是这么做的!

glut opengl库提供的初始化方法(GlutInit)扫描与 glut 相关的参数,并通过向前移动 argv 中的后续元素(移动指针,而不是实际字符串)并递减 argc 来清除它们

2.1

glutInit glutInit 用于初始化 GLUT 库。

使用

void glutInit(int *argcp, char **argv);

argcp

指向
程序来自 main 的未修改的 argc 变量。 返回时,值
argcp 指向的将被更新,因为 glutInit 提取任何
用于 GLUT 库的命令行选项。

argv

该计划的
main 中未修改的 argv 变量。 与 argcp 一样,argv 的数据将
被更新,因为 glutInit 提取任何命令行选项
被 GLUT 库理解。

Some libraries do this!

The initialization method provided by the glut opengl library (GlutInit) scans for glut related arguments, and clears them by moving the subsequent elements in argv forward (moving the pointers, not the actual strings) and decrementing argc

2.1

glutInit glutInit is used to initialize the GLUT library.

Usage

void glutInit(int *argcp, char **argv);

argcp

A pointer to the
program's unmodified argc variable from main. Upon return, the value
pointed to by argcp will be updated, because glutInit extracts any
command line options intended for the GLUT library.

argv

The program's
unmodified argv variable from main. Like argcp, the data for argv will
be updated because glutInit extracts any command line options
understood by the GLUT library.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文