为什么argc不是常数?

时间:2013-12-13 03:09:35

标签: c++ const main argc effective-c++

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

作为Effective C++第3项规定“尽可能使用const”,我开始思考“为什么不将这些'常数'参数设为const”?

是否存在在程序中修改argc的值的情况?

7 个答案:

答案 0 :(得分:112)

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

某些UNIX API(例如getopt)实际上操作argv[],因此也无法使const成为getopt

(旁白:有趣的是,虽然argv[]的原型表明它不会修改getopt但可能修改指向的字符串,但Linux手册页指示const置换其参数,it appears they know they're being naughty .Open Group的手册页没有提到这种排列。)

argc放在argv// print out all the arguments: while (--argc) std::cout << *++argv << std::endl; 上并不会带来太大的收益,这会使一些老派的编程习惯无效,例如:

{{1}}

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

答案 1 :(得分:36)

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

  

5.1.2.2.1程序启动

     

¶1程序启动时调用的函数名为main。实施宣布否   这个功能的原型。它应该使用返回类型int和no来定义   参数:

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

或有两个参数(此处称为argcargv,但可能有任何名称   使用,因为它们是声明它们的函数的本地函数):

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

或等同物; 10)或其他一些实施定义的方式。

     

¶2如果声明它们,main函数的参数应遵循以下规则   约束:

     
      
  • argc的值应为非负值。
  •   
  • argv[argc]应为空指针。
  •   
  • 如果argc的值大于零,则数组成员argv[0]通过   argv[argc-1]包含应包含指向字符串的指针   程序启动前主机环境实现定义的值。该   意图是在程序启动之前为程序提供信息   来自托管环境中的其他地方。如果主机环境不具备   为字符串提供大写和小写的字母,实现   应确保以小写字母收到字符串。
  •   
  • 如果argc的值大于零,则argv[0]指向的字符串   代表程序名称; argv[0][0]如果是,则为空字符   程序名称不能从主机环境中获得。如果argc的值是   大于一,argv[1]通过argv[argc-1]指向的字符串   代表程序参数。
  •   
  • 参数argcargv以及argv数组指向的字符串应   可以由程序修改,并在程序之间保留它们最后存储的值   启动和程序终止。
  •   
     

10)因此,int可以替换为定义为int的typedef名称,或者argv的类型可以写为   char **argv,等等。

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

答案 2 :(得分:23)

argc通常不是常量,因为main()的函数签名在const之前。

由于argc是一个堆栈变量,因此更改它不会影响您自己的命令行处理以外的任何内容。

如果您愿意,您当然可以自由声明const

答案 3 :(得分:8)

正式参数的顶级const不是函数类型的一部分。您可以根据需要添加或删除它:它只影响您可以使用函数实现中的参数执行的操作。

因此,对于argc,您可以自由添加const

但对于argv,如果不更改功能签名,则无法创建字符数据const。这意味着它不是标准main函数签名之一,并且不必被识别为main函数。所以,不是一个好主意。


在非玩具程序中不使用标准main参数的一个很好的理由是,在Windows中,它们无法表示实际的程序参数,例如具有国际字符的文件名。这是因为在Windows中,它们是由非常强大的约定编码为Windows ANSI。在Windows中,您可以根据GetCommandLine API函数实现更多可移植的参数访问工具。


总结一下,没有什么可以阻止您将const添加到argc,但const上最有用的argv - 会给你一个非标准{{1}功能,很可能不被认可。令人高兴的是(以讽刺的方式),有充分的理由不使用标准的main参数用于便携式严重代码。很简单,对于实践中他们只支持旧的ASCII,只有英文字母。

答案 4 :(得分:4)

main的签名有点像C的历史文物。历史上C没有const

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

答案 5 :(得分:2)

因为argc是一个局部变量(并且在C ++中,不是引用或其他东西),并且因为main的特殊位置意味着向后兼容性shenanigans授予它大量的回旋余地没有令人信服的理由强制应用程序使其成为常量。

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,C示例:

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

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

main(const int argc) {}

答案 6 :(得分:1)

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

当您定义自己的函数和相关原型时,您知道可以创建哪些参数const以及您的函数将修改哪些参数。

采取极端,您可以声明所有函数的所有参数都应声明为const,然后如果您有理由更改它们(例如,减少索引以搜索数组),那么'' d必须创建本地非const变量并将const参数'值复制到这些变量中。这使得繁忙的工作和额外的LOC没有真正的好处。如果您没有修改参数的值,那么一个体面的静态分析器将会启动,并建议您创建参数const