为什么argc不是一个常量?

int main( const int argc , const char[] const argv) 

由于有效的C ++项目#3陈述“尽可能使用const”,我开始思考“为什么不使这些'常量'参数const ”?。

在程序中是否有任何argc的值被修改的场景?

在这种情况下,历史是一个因素。 C将这些input定义为“不常量”,与现有C代码(很大一部分)的兼容性是C ++的早期目标。

一些UNIX API,比如getopt ,实际上是在操作argv[] ,所以它也不能因为这个原因而变成const

(另外:有趣的是,虽然getopt的原型build议不会修改argv[]但可能会修改指向的string,Linux手册页指出getopt对其参数进行置换,而且看起来他们知道他们是调皮的 。 Open Group的手册页没有提到这个排列。)

const放在argcargv不会买太多东西,而且会使一些旧式的编程实践失效,比如:

 // print out all the arguments: while (--argc) std::cout << *++argv << std::endl; 

我用C写了这样的程序,我知道我并不孤单。 我从某处复制了这个例子。

C标准(ISO / IEC 9899:2011)说:

5.1.2.2.1程序启动

¶1程序启动时调用的函数名为main 。 这个实现声明了这个函数没有原型。 它应该用int的返回types来定义,并且不带参数:

 int main(void) { /* ... */ } 

或者带有两个参数(这里称为argcargv ,尽pipe可以使用任何名称,因为它们是声明它们的函数的本地):

 int main(int argc, char *argv[]) { /* ... */ } 

或同等学历; 10)或者其他一些实现定义的方式。

¶2如果声明它们, main函数的参数应遵守以下约束条件:

  • argc的值应该是非负的。
  • argv[argc]应该是一个空指针。
  • 如果argc的值大于零,则argv[0]argv[argc-1]包含的数组成员应该包含指向string的指针,这些string在程序启动之前由主机环境给出实现定义的值。 其目的是向程序提供在程序启动之前从托pipe环境中的其他地方确定的信息。 如果主机环境不能提供大小写字母的string,则实现应确保string以小写forms接收。
  • 如果argc的值大于零,则argv[0]指向的string表示程序名称; 如果程序名称在主机环境中不可用,则argv[0][0]应为空字符。 如果argc的值大于1,则argv[1]argv[argc-1]指向的string表示程序参数。
  • 参数argcargv以及argv数组所指向的string应该可以被程序修改,并且在程序启动和程序终止之间保留它们的最后存储的值。

10)因此, int可以被定义为int的typedef名称replace,或者argv的types可以被写为char **argv ,依此类推。

请注意最后一个要点。 它说argcargv都应该是可以修改的。 他们不必修改,但可能会被修改。

argc通常不是一个常量,因为main()前置const函数签名。

由于argc是一个堆栈variables,所以更改它不会影响除您自己的命令行处理以外的其他任何操作。

如果你愿意,你当然可以自由地声明它为const

forms参数上的顶层const不是函数types的一部分。 你可以随意添加或删除它:它只影响你可以用函数实现中的参数做什么。

所以对于argc你可以自由添加一个const

但是对于argv你不能在不改变函数签名的情况下使字符数据为const 。 这意味着它不是标准的mainfunction签名之一,并且不必被认为是mainfunction。 所以,不是一个好主意。


在非玩具程序中不使用标准main参数的一个很好的理由是,在Windows中,它们不能表示实际的程序参数,例如具有国际字符的文件名。 这是因为在Windows中,它们被编码为Windows ANSI的非常强大的约定。 在Windows中,您可以使用GetCommandLine API函数来实现一些更便携的参数访问设施。


总结一下,没有什么能阻止你将const添加到argc ,但是对argv最有用的const将会给你一个非标准的main函数,很可能不被认为是这样。 令人高兴的是(具有讽刺意味的是,)对于便携式严肃代码, 没有使用标准的main论据是有充分的理由的。 很简单,实际上他们只支持旧的ASCII,只有英文字母。

main的签名是C的一个历史人造物。 历史上C没有const

但是,你可以声明你的参数为const因为const的效果只是编译时间。

因为argc是一个局部variables(在C ++中,不是一个引用或者某个东西),而且由于main的特殊位置意味着向后兼容性的恶意赋予它一个巨大的回旋余地,没有强制性的理由来迫使应用程序使其成为const。

 main() {} int main() {} main() { return 0; } main(int argc, char* argv[]) { return 0; } int main(const int argc, const char** argv) { /* no return*/ } 

这些和许多其他变体将在各种C和C ++编译器上进行编译。

所以最终并不是说argc不是const,只是它不是必须的,但它可以是你想要的。

http://ideone.com/FKldHF ,例如:

 main(const int argc, const char* argv[]) { return 0; } 

http://ideone.com/m1qc9c,C ++示例

 main(const int argc) {} 

除了历史的原因之外,保持argc和argv不是const一个好的理由是编译器实现并不知道你要用main的参数做什么,它只知道它必须给你这些参数。

当你定义自己的函数和相关的原型时,你知道哪些参数可以做const ,哪些参数可以修改。

非常极端,你可以声明所有函数的所有参数都应该声明为const ,然后如果你有理由改变它们(例如递减一个索引来search一个数组) constvariables并将const参数的值复制到这些variables中。 这使忙碌的工作和额外的LOC没有真正的好处。 如果你不修改参数的值,一个体面的静态分析器将会启动,并build议你使参数为const

Interesting Posts