argv [n]是否可写?

时间:2014-09-09 05:48:22

标签: c language-lawyer

C11 5.1.2.2.1 / 2说:

  

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

我对此的解释是它指定:

int main(int argc, char **argv)
{
    if ( argv[0][0] )
        argv[0][0] = 'x';   // OK

    char *q;
    argv = &q;              // OK
}

然而它没有说什么:

int main(int argc, char **argv)
{
    char buf[20];
    argv[0] = buf;
}

是否允许argv[0] = buf;

我可以看到(至少)两个可能的论点:

  • 以上引述故意提到argvargv[x][y]但不是argv[x],所以意图是它不可修改
  • argv是指向非const个对象的指针,所以在没有相反的特定措辞的情况下,我们应该假设它们是可修改的对象。

4 个答案:

答案 0 :(得分:6)

IMO,像argv[1] = "123";这样的代码是UB。


  

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

回想一下,{C}创建后const进入C多年。

就像char *s = "abc"; const char *s = "abc";一样有效。不需要const,因为引入const会过多地破坏现有代码。

同样,即使今天argv应被视为char * const argv[]或其他一些签名constconst中缺少char *argv[]也无法完成指定constargvargv[]的{​​{1}} - 需求。 argv[][] - 需要需要由规范驱动。

从我的阅读中,由于规范在这个问题上没有提及,所以它是UB。

  

本国际标准中未明确的行为在“未定义的行为”或“省略任何明确的行为定义”“§42

中表示

[编辑]:

const是一个非常特殊的函数C.在main()中可能允许或不允许其他函数允许的内容。 C规范详细说明了给出了不需要的签名main()的参数。与C中的其他函数不同,int argc, char *argv[]可以具有备用签名main(),也可能具有其他签名。 int main(void)不可重入。由于C规范不再详细说明可以修改的内容:main()argcargv,因此问argv[][]是否可修改是合理的从规范中省略代码可以。

考虑到argv[]的特殊性和省略指定main()可修改,保守的程序员会将此灰色视为UB,等待未来的C规范澄清。


如果argv[]在给定平台上可修改,则argv[i]的范围当然不应超过i

由于“argc-1应为空指针”,因此将argv[argc]分配给argv[argc]以外的其他内容似乎是违规行为。

尽管字符串是可修改的,但代码不应超过原始字符串的长度。

NULL

答案 1 :(得分:0)

argc只是一个int,可以不受任何限制地修改。

argv是可修改的char **。这意味着argv[i] = x有效。但它没有说argv[i]本身可以修改的任何内容。所以argv[i][j] = c会导致未定义的行为。

C标准库的getopt函数确实修改了argc和argv,但从不修改实际的char数组。

答案 2 :(得分:-1)

明确提到argvargv[x][x]是可修改的。如果argv是可修改的,那么它可以指向char数组的另一个第一个元素,因此argv[x]可以指向另一个字符串的第一个元素。最终argv[x]也可以修改,这可能是没有必要在标准中明确提及它的原因。

答案 3 :(得分:-1)

答案是argv是一个数组,是的,它的内容是可修改的。

密钥在同一部分中较早:

  

如果argc的值大于零,则数组成员argv [0]通过   argv [argc-1] inclusive应包含指向字符串的指针   程序启动前主机环境实现定义的值。

很明显,argv被认为是一个特定长度的数组(argc)。然后* argv是指向该数组的指针,已经衰减为指针。

在此上下文中,请注意“argv应该是可修改的......并保留其内容'明确地希望该数组的内容可以修改。

我承认措辞中仍然存在一些含糊之处,特别是如果修改了argc会发生什么。


为了清楚起见,我所说的是我将这种语言理解为含义:

  

[argv [array]的内容和argv数组指向的字符串应该是可修改的......

因此,数组中的指针和它们指向的字符串都在读写内存中,通过更改它们不会造成任何损害,并且两者都会在程序的生命周期中保留它们的值。我希望在所有主要的C / C ++运行时库实现中都能找到这种行为,毫无例外。这不是UB。

模棱两可的是提到了argc。很难想象argc(看起来只是一个局部函数参数)的值无法改变的任何目的或任何实现,为什么要提到它呢?标准清楚地说明一个函数可以改变其参数的值,那么为什么在这方面特别处理argc呢?正是这种意外提到的argc引发了对argv的这种担忧,否则它将无法通过。从句子中删除argc,模糊性消失。