入口点
在计算机编程中,入口点是在程序中执行第一条指令的地方,和程序访问命令行参数的地方。要开始一个程序的执行,装载器或操作系统会将控制权传递到它的入口点。(在引导期间,操作系统自身就是这个程序)。这标志着从装载时(和动态连接时,如果存在的话)到运行时的转变。
对于某些操作系统和编程语言,入口点是运行时库,它是一组对语言的支持函数。库代码初始化程序并且接着把控制权传递给程序本身。在其他情况下,程序自身可以初始化运行时库。在简单的系统中,执行开始于第一条语句,这常见于解释型语言,简单的可执行格式,和引导装载器中。在其他情况下,入口点是在某个其他已知内存地址,这可以是绝对地址或相对地址(偏移量)。
可作为替代选择,程序的执行可以开始于命名点,要么是编程语言或操作系统定义的约定名字,要么是调用者指定的名字。在很多C家族语言中,这是叫做main
的函数;作为结果,入口点经常叫做主函数。在JVM语言比如Java中,入口点是叫做main
的静态方法;在CLI语言比如C#中,入口点是叫做Main
的静态方法[1]。
用法
在现代的计算机体系中,CPU 下一次要执行的指令地址由一个寄存器指出,称为“指令指针”(Instruction Pointer、IP)或“程序计数器”(Program Counter、PC)。该寄存器在系统上电或复位时由硬件电路置为某地址值,位于该地址的程序即可视为整个程序的入口点。这个概念一般只在嵌入式程序(固件)或操作系统的引导代码中使用,因为给非嵌入式系统写的程序通常包含数量庞大的机器指令、以至于关注一两个机器指令是没有意义的。
而所谓的“可执行”,说白了就是这个文件存储了一些信息、好创造某个让程序可以开始运行的内存状态,而操作系统装载并创建进程的步骤就是把这个满是机器指令的内存状态复原出来并开始运行。因此,可执行文件中的“程序入口点”表示把加载进来的哪个地址当作“开始运行”的那一条指令。
编程语言
C/C++
int main(void)
int main()
int main(int argc, char *argv[])
main
的兩個環境參數:argc
(argument count)與argv
(argument vector)[2],兩者個別自程式的指令列給予參數的數量與參數陣列的指標位址。argc
與argv
這兩個參數的名稱,在程式語言的命名規則底下,雖然可以依照使用者的喜好自行定義,但是一般在使用上,還是會以現有的名稱argc
與argv
來進行程式的編寫。其他具有相依平台的格式也可以被C與C++標準所接受;例如,UNIX(非POSIX.1)與Microsoft Visual C++有第三個參數,是用來接收程式的環境變數,利用其他方法存取環境變數,可以使用stdlib.h
標頭檔案定義的getenv
函式:
int main(int argc, char *argv[], char *envp[])
Mac OS X與Apple Darwin有第四個參數,它含有作業系統支援性的資訊,例如執行二進制檔案的路徑:[3]
int main(int argc, char *argv[], char *envp[], char *apple[])
由main
傳給作業系統的傳回值,代表程序處理的結束狀態,在C的標準裡有定義兩個傳回值:EXIT_SUCCESS
(通常是整數零 0值)與EXIT_FAILURE
。由於在實作上考量到各種的可能性,所以依照可能會發生的狀態來定義傳回值。
依照一般使用的規則,指令列參數的第一個元素就是程式檔案的名稱,假如程式檔案的名稱為rm.exe
,當使用者在指令列輸入rm file
後,使用者介面的程式shell會初始化rm.exe
處理程序,設定環境變數argc = 2
以及argv = ["rm", "file"]
。
main
這個名稱是一個特有的名稱;正常來說,使用者在每個C與C++程式自定的函式名稱,必須不同於main
這個名稱。
在C++裡,main
一定是在全域的名稱空間內(例如:::main
),它不可以是類別或是實體的成員函式。
由於前置處理器的關係,以下main
函式原始碼可適用於Microsoft Visual C++與Dev-C++:
#ifndef _MSC_VER
int
#else
void
#endif
main(int argc, char** argv)
{
// 程式碼
system("PAUSE");
return
#ifndef _MSC_VER
EXIT_SUCCESS
#endif
;
}
WinMain
以微軟視窗為基礎的程式設計上,WinMain
[4]函式是視窗程式的進入點,函式原型如下所示:
int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow);
.Net 语言(C#、VB 等)
以C#編寫的程式,在开始執行時CLR會先去尋找帶有.entrypoint
IL標示的靜態方法,而這個靜態方法可能沒有參數,或是只有單一string[]
型態的參數,而且還有void
或是int
型態的傳回值,找到後才會執行這個方法,而這個方法就是主函式。[5]
static void Main();
static void Main(string[] args);
static int Main();
static int Main(string[] args);
指令列參數會被引入到args
變數內,引入的方式與Java相類似。但是,針對有整數傳回值的Main
而言,引入的方式類似C/C++,而指令列參數會被當成處理程序的結束狀態,傳回給作業系統或是執行它的外部環境。
同为 .net 语言的 Visual Basic .NET 大体也是一样。不过不同的是,旧版本 Visual Basic 的程序可以选择在执行默认初始化步骤后以一个窗体启动,此时的主函数是不可见的;新版本为了兼容性和简化编码工作而保留了这个特性。
Java
Java程式語言是以main 方法來當做程式開始的起點,方法如下:
public static void main(String[] args)
命令列指定參數是args。如同C和C++一樣,「main」也是唯一的。Java的main方法無任何的傳回值。
Pascal
Pascal的主要程序是不需命名的。因為Pascal程式的程序和函式在編寫程式上比C、C++或是Java更加嚴格,在程式裡主要程序通常才是最後的程序。Pascal沒有main或是其他相類似的關鍵字。
以下是Hello world範例:
procedure hello() begin
writeln('Hello world')
end;
begin
hello()
end.
參考資料
- Wagner, Bill. . docs.microsoft.com. 2017-08-01 [2018-12-03]. (原始内容存档于2020-11-11) (美国英语).
- argv: the vector term in this variable's name is used in traditional sense to refer to strings.(基本上這個參數是以傳統的方法對參數的字串進行存取的動作,相當於指標陣列)
- . [2009-10-28]. (原始内容存档于2015-12-22).
- . [2009-10-28]. (原始内容存档于2018-08-21).
- . [2009-11-04]. (原始内容存档于2008-02-04).
外部連結
- Python main()函式 (页面存档备份,存于)