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

我的应用程序可能传递了大量的参数,我希望避免将参数复制到过滤列表中的内存。 我想在适当的位置过滤它们,但我很确定混淆argv数组本身,或它指向的任何数据,可能是不可取的。 有什么建议?

一旦将argv传递给main方法,就可以像对待任何其他C数组一样对待它 – 根据需要随意更改它,只需要知道你正在做什么。 除了在代码中明确使用它的内容之外,数组的内容对返回代码或程序的执行没有影响。 我想不出任何理由不特别对待它是“明智的”。

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

C99标准说这是关于修改argv (和argc ):

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

C标准的最新草案(N1256)规定mainfunction有两种允许forms:

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

但关键是“或以其他一些实施方式”的条款。 这对我来说似乎是标准的漏洞,足以驱动半挂车通过。

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

 pax> cat qq.c #include  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  int main (int c, char *v[]) { *v[1] = 'X'; printf ("[%s]\n", v[1]); return 0; } pax> gcc -o qq2 qq2.c ; ./qq2 [Xello] 

我认为这也是C ++的情况。 目前的草案规定:

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

但它并没有明确地禁止其他变体,所以你可以在C ++中接受一个"const"版本(实际上,g ++也是如此)。

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

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

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

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

但是,根据argv [0]更改程序的行为本身就是一个非常糟糕的想法,其中可移植性是一个问题。

除此之外,您可以像对待任何其他arrays一样对待它。 正如Jonathan所说,GNU getopt()非破坏性地置换参数列表,我已经看到了其他getopt()实现,这些实现甚至可以对参数进行序列化甚至散列(当程序接近ARG_MAX时很有用)。

小心你的指针算术。

有些图书馆这样做!

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

2.1

glutInit glutInit用于初始化GLUT库。

用法

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

argcp

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

ARGV

该程序的未经修改的argv变量来自main。 与argcp一样,argv的数据也会更新,因为glutInit会提取GLUT库理解的任何命令行选项。

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

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

删除您已预处理的参数,这样的内容将起作用:

(许多错误条件没有检查,“ – 特殊”其他第一个arg没有检查,等等。毕竟,这只是一个概念演示。)

 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 

但是请看完全操作:( libiberty库中用于操作argv样式向量的部分)

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

它是授权GNU LGPL。