學過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(int,?char?**,?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;
}
?