M.M*_*M.M 32 c language-lawyer
C11 5.1.2.2.1/2说:
数组指向的参数
argc
和argv
字符串argv
应由程序修改,并在程序启动和程序终止之间保留它们最后存储的值.
我对此的解释是它指定:
int main(int argc, char **argv)
{
if ( argv[0][0] )
argv[0][0] = 'x'; // OK
char *q;
argv = &q; // OK
}
Run Code Online (Sandbox Code Playgroud)
但它没有说什么:
int main(int argc, char **argv)
{
char buf[20];
argv[0] = buf;
}
Run Code Online (Sandbox Code Playgroud)
被argv[0] = buf;
允许的?
我可以看到(至少)两个可能的论点:
argv
,argv[x][y]
但不是argv[x]
,所以意图是它不可修改argv
是指向非const
对象的指针,因此在没有相反的特定措辞的情况下,我们应该假设它们是可修改的对象.该argv
数组不需要是可修改的(但在实际实现中可能是可修改的)。这是一个有意的措辞,并在1998年的n849会议上得到了重申:
https://www.open-std.org/jtc1/sc22/wg14/www/docs/n849.htm
PUBLIC REVIEW COMMENT #7
[...]
Comment 10.
Category: Request for information/clarification
Committee Draft subsection: 5.1.2.2.1
Title: argc/argv modifiability, part 2
Detailed description:
Is the array of pointers to char pointed to by argv modifiable?
Response Code: Q
This is currently implictly unspecified and the committee
has chosen to leave it that way.
Run Code Online (Sandbox Code Playgroud)
此外,还提出了两项单独的提案,分别修改和扩充措辞。两人都被拒绝了。有兴趣的读者可以通过搜索“argv”找到它们。
琐事: Kernighan 和 Ritchie 的《C 编程语言》第二版(“K&R2”)中的一个示例与此相冲突。它在第117页,相关代码行是:
while (c = *++argv[0])
Run Code Online (Sandbox Code Playgroud)
它会增加参数向量本身内部的指针以逐步遍历字符串的字符。
IMO,代码就像argv[1] = "123";
是UB.
"参数argc和argv以及argv数组指向的字符串应该可由程序修改,并在程序启动和程序终止之间保留它们最后存储的值." C11dr§5.1.2.2.12
回想一下,const
在C创作之后很多年才进入C阶段.
很像char *s = "abc";
是有效的,当它应该是const char *s = "abc";
.不需要const
太多的需要,否则太多的现有代码将被引入const
.
同样,即使argv
今天,应考虑char * const argv[]
或其他一些与签名const
,缺乏const
在char *argv[]
未完成指定const
的-ness需求argv
,argv[]
或argv[][]
.该const
-ness需求将需要在规范中来驱动.
从我的阅读中,由于规范在这个问题上保持沉默,因此它是UB.
未定义的行为在本国际标准中以"未定义的行为"或" 省略任何明确的行为定义 " 一词另有说明"§42
[编辑]:
main()
是一个非常特殊的功能是C.在其他功能允许的范围内可能允许也可能不允许main()
.C规范详细说明了给出int argc, char *argv[]
不需要的签名的参数. main()
与C中的其他函数不同,它可以具有备用签名,也可能具有其他签名int main(void)
. main()
不是可重入的.由于C时的参数超出其办法详细说一下可以修改:argc
,argv
,argv[][]
,它是合理的问题,如果argv[]
是由于修改从规范断言代码可以将其忽略.
鉴于main()
指定argv[]
可修改的特殊性和疏忽性,保守的程序员会将此灰色视为UB,等待未来的C规范澄清.
如果argv[i]
在给定平台上可以修改,那么当然i
不应超过范围argc-1
.
由于" argv[argc]
应该是一个空指针",分配argv[argc]
给NULL
看似违反的东西.
尽管字符串是可修改的,但代码不应超过原始字符串的长度.
char *newstr = "abc";
if (strlen(newstr) <= strlen(argv[1]))
strcpy(argv[1], newstr);
Run Code Online (Sandbox Code Playgroud)