学过C/C++语言的都知道程序的执行从main函数开始(先不说static对象和CRT),大部分学过C/C++的也都知道main可以有int main()和int main(int argc, char**argv)的参数格式,有不少人还知道int main(int, char**, char**)的参数形式,返回值也可以为void,但是为什么C/C++ compiler能够支持这些格式呢?在初学C的时候,我以为是编译器内置的功能来支持

近日研究VC的CRT,发现原来是通过调用规范(calling coventions)实现的。
调用规范分为参数传递次序,调用栈维护,命名修饰和大小写转换4个规范组成。

大部分的C语言编译器(至少是在x86架构上)遵循以下的规范
命名修饰和大小写转换:无论函数的signature是什么样子,在编译时会将名为“Xxxx”的函数转换为“_Xxxx”的形式,即在函数名前面加上“_”,大小写不变,也就是说不管是什么形式的main函数,有没有返回值,有多少个参数都会在编译时转换为_main。因此虽然在CRT中使用的是
int __cdecl main(intchar **char **);

的形式声明的main函数,但是在链接的时候无论是什么形式的main都符合要求,只不过除了在文章开始提到的3种形式有意义外,其他的参数格式要么是得到无意义的值,要么还会溢出调用栈(使用超过3个参数)
测试代码如下:

int main(int a1, char* a2, unsigned long a3, float a4, double a5, unsinged int a6)
{
 printf(
"Hello World!\n");
 
return 0;
}