最近(2016年1月,如果问题持续时间足够长),我们提出问题Are the strings in argv modifiable?
在this回答的评论部分,我们(@ 2501和我)认为是否真的是字符串(一个示例字符为**argv
)可以修改或者指向字符串的指针(示例指针为*argv
)。
适当的标准报价来自C11标准草案N1570,§5.1.2.2.1/ 2:
参数
argc
和argv
以及指向的字符串argv
数组应该由程序修改,并保留它们 程序启动和程序终止之间的最后存储值。
argv
可修改指向字符串的指针是什么?
答案 0 :(得分:6)
正如问题中引用的OP,C11标准明确指出argc
和argv
变量以及argv
数组指向的字符串是可修改的。无论这些指针是否可修改,问题都在眼前。该标准似乎没有明确地以某种方式陈述它。
关于标准中的措辞,有两点需要注意:
如果指针应该是不可变的,那么标准可以通过要求将main声明为int main(int argc, char *const argv[])
,而在另一个问题的答案中将haccks mentioned声明为GTK+ gtk_init()
来表明。
标准中没有任何地方const
与argv
相关联的事实似乎是故意的。也就是说,缺少const
似乎不是可选的,而是由标准决定的。
标准一致地调用argv
数组。修改数组是指修改其成员。因此,很明显标准中的措辞是指修改argv
数组中的成员,当它指出argv
是可修改的时。
另一方面,C中的数组参数(基于C11草案N1570,§6.7.6.3p7)“应调整为'限定指向类型'的指针”。因此,以下代码
int foo(int x[2], int y[2])
{
if (x[0] > y[0])
x = y;
return x[1];
}
是有效的C11,因为x
和y
分别调整为int *x
和int *y
。 (这也在C11草案N1570中重申,§6.3.2.1p3:“... array ...被转换为类型'指向类型的指针'的表达式,指向数组的初始元素。 。“)。
显然,如果将x
和y
声明为本地或全局数组,而不是函数参数,则不会相同。
就语言 - 律师主义而言,我会说标准不会以这种或那种方式陈述,尽管暗示指针也应该是可修改的。因此,作为OP的答案:两者。
在实践中,argv
数组中的指针有一个很长的传统可以修改。许多库都有初始化函数,它们指向argc
和指向argv
数组的指针,其中一些函数会修改argv
数组中的指针(删除特定于库的选项) );例如MPI_Init()
和getopt()
(尽管至少OpenMPI明确声明它不会检查或修改它们)。寻找参数声明(int *argc, char ***argv)
;唯一的原因 - 假设意图是使用main()
从(&argc, &argv)
调用 - 是修改指针,从命令中解析和删除特定于库的命令行参数 - 行参数,根据需要修改argc
和argv
中的指针。
(我最初声称POSIX 中的readproctitle工具依赖指向可修改的指针 - 这个功能可以追溯到1980年,被大多数Unix风格采用,并在POSIX中标准化。 1997年的2 - 但这是不正确的,正如Jonathan Leffler在评论中指出的那样:POSIX getopt()
不会修改实际的指针;只有GNU getopt()
会这样做,而且仅在{{1}时没有设置环境变量。除非设置了POSIXLY_CORRECT
,否则GNU getopt_long()
和BSD getopt_long()
都会修改指针,但与POSIXLY_CORRECT
相比,它们更年轻,更不普遍。)
在Unix版本中,修改getopt()
数组,指向的字符串的内容被认为是“可移植的”,并且在进程列表中可以看到修改后的字符串。 DJB的daemontools包{{3}}就是一个有用的例子。 (请注意,字符串必须就地修改,并且无法扩展,以使更改在进程列表中可见。)
所有这些都表明了一个非常悠久的传统,基本上几乎从C作为编程语言诞生以来,并且肯定在C的标准化之前,处理argv[]
,argc
,{中的指针{1}}数组,以及这些指针指向的字符串的内容,可以修改。
因为C标准的目的不是定义新的行为,而是编写跨实现的现有行为(以提高可移植性和可靠性等),似乎可以安全地假设它是标准部分的无意识遗漏编写器没有明确指定argv
数组中的指针可修改。任何其他东西都会破坏传统,并明确违背POSIX标准(它也旨在促进跨系统的可移植性,并扩展未包含在ISO C标准中的C功能)。
答案 1 :(得分:1)
指针是否可修改取决于指针的constness。参数argv
声明为char *argv[]
或char **argv
。这取决于环境,他们是否将其视为char *const argv[]
(我不知道)。