VS2019中CRT以3个参数调用main()未触发参数数量错误编译提示的原因探究
这个问题的核心在于标准C/C++对main函数的规定,以及VS运行时(CRT)的实现扩展和用户代码编译检查规则的差异,咱们一步步拆解:
1. 标准与VS的main函数签名扩展
C和C++标准规定,main函数的合法签名只有两种:
int main()int main(int argc, char** argv)
但标准同时允许实现定义的扩展——也就是说,编译器/运行时可以支持额外的参数。VS的CRT确实支持第三个参数:char** envp(指向环境变量数组的指针),这是VS对标准的扩展实现。
CRT里的invoke_main调用main(__argc, __argv, _get_initial_narrow_environment()),正是用了这个扩展签名,这是VS运行时内部约定好的,完全符合它自己的实现规则。
2. 用户代码编译检查的逻辑
你示例里的代码注释掉了main的参数声明,相当于你定义的是:
int main() { ... }
这时候编译器会认为你的main函数是无参的。当你在函数内部调用main(argc, argv, env)时,编译器会检查你调用的函数签名和定义是否匹配——无参函数却传了3个参数,自然会触发C2660错误(函数不接受3个参数)。
如果你的需求是想用带3个参数的main,只需要明确声明扩展签名即可:
int main(int argc, char** argv, char** envp) { // 你的代码逻辑 }
这时候你再内部调用main(argc, argv, envp),编译器就不会报错了(不过递归调用main在C++里是未定义行为,不建议这么做)。
3. 为什么CRT的调用不受用户代码编译检查约束?
CRT的invoke_main是运行时库的内部代码,它是和VS编译器协同开发的,属于编译器/运行时的一部分。它对main的调用是基于VS支持的扩展签名来实现的,而且这部分代码是提前编译好的,不会和你的用户代码一起做普通的编译检查。简单来说,它是“自己人”,知道VS允许main有第三个参数,所以不会触发错误。
另外要注意,你示例里的变量命名也有问题:argc被定义成了char**类型,argv是int类型,这和标准的参数命名/类型完全相反,即使你声明了3参数的main,这样的变量传递也会导致类型不匹配的问题,建议修正变量名和类型哦。
内容的提问来源于stack exchange,提问作者Kozue Mukai

