是否可以更改argv或是否需要创建它的调整副本?
我的应用程序可能传递了大量的参数,我希望避免将参数复制到过滤列表中的内存。 我想在适当的位置过滤它们,但我很确定混淆argv数组本身,或它指向的任何数据,可能是不可取的。 有什么建议?
一旦将argv传递给main方法,就可以像对待任何其他C数组一样对待它 – 根据需要随意更改它,只需要知道你正在做什么。 除了在代码中明确使用它的内容之外,数组的内容对返回代码或程序的执行没有影响。 我想不出任何理由不特别对待它是“明智的”。
当然,您仍然需要注意意外访问超出argv范围的内存。 像普通Carrays一样可以访问它的另一面是,它也像任何其他正常的Carrays一样容易出现访问错误。 (感谢所有在评论和其他回复中指出这一点的人!)
C99标准说这是关于修改argv
(和argc
):
参数argc和argv以及argv数组指向的字符串应该可由程序修改,并在程序启动和程序终止之间保留它们最后存储的值。
C标准的最新草案(N1256)规定main
function有两种允许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。