入口點

<image>

在電腦編程中，入口點是在程序中執行第一條指令的地方，和程序訪問命令行參數的地方。要開始一個程序的執行，裝載器或作業系統會將控制權傳遞到它的入口點。（在引導期間，作業系統自身就是這個程序）。這標誌著從裝載時（和動態連接時，如果存在的話）到運行時的轉變。

對於某些作業系統和程式語言，入口點是運行時庫，它是一組對語言的支持函數。庫代碼初始化程序並且接著把控制權傳遞給程序本身。在其他情況下，程序自身可以初始化運行時庫。在簡單的系統中，執行開始於第一條語句，這常見於解釋型語言，簡單的可執行格式，和引導裝載器中。在其他情況下，入口點是在某個其他已知記憶體地址，這可以是絕對地址或相對地址（偏移量）。

可作為替代選擇，程序的執行可以開始於命名點，要麼是程式語言或作業系統定義的約定名字，要麼是調用者指定的名字。在很多C家族語言中，這是叫做`main`的函數；作為結果，入口點經常叫做主函數。在JVM語言比如Java中，入口點是叫做`main`的靜態方法；在CLI語言比如C♯中，入口點是叫做`Main`的靜態方法。

## 用法

在現代的計算機體系中，CPU 下一次要執行的指令地址由一個寄存器指出，稱為「指令指針」（Instruction Pointer、IP）或「程序計數器」（Program Counter、PC）。該寄存器在系統上電或復位時由硬體電路置為某地址值，位於該地址的程序即可視為整個程序的入口點。這個概念一般只在嵌入式程序（固件）或作業系統的引導代碼中使用，因為給非嵌入式系統寫的程序通常包含數量龐大的機器指令、以至於關注一兩個機器指令是沒有意義的。

而所謂的「可執行」，說白了就是這個文件存儲了一些資訊、好創造某個讓程序可以開始運行的記憶體狀態，而作業系統裝載並創建進程的步驟就是把這個滿是機器指令的記憶體狀態復原出來並開始運行。因此，可執行文件中的「程序入口點」表示把加載進來的哪個地址當作「開始運行」的那一條指令。

## 程式語言

### C/C++

在C語言或C++程式語言，`main`的函式原型如下所示：

```cpp
int main(void)
int main()
int main(int argc, char *argv[])
```

`main`的兩個環境參數：`argc`（argument count）與`argv`（argument vector），兩者個別自程式的指令列給予參數的數量與參數陣列的指標位址。`argc`與`argv`這兩個參數的名稱，在程式語言的命名規則底下，雖然可以依照使用者的喜好自行定義，但是一般在使用上，還是會以現有的名稱`argc`與`argv`來進行程式的編寫。其他具有相依平台的格式也可以被C與C++標準所接受；例如，UNIX（非POSIX.1）與Microsoft Visual C++有第三個參數，是用來接收程式的環境變數，利用其他方法存取環境變數，可以使用`stdlib.h`標頭檔案定義的`getenv`函式：

```c
int main(int argc, char *argv[], char *envp[])
```

Mac OS X與Apple Darwin有第四個參數，它含有作業系統支援性的資訊，例如執行二進制檔案的路徑：

```c
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++：

```cpp
#ifndef _MSC_VER
int
#else
void
#endif
main(int argc, char** argv)
{
    // 程式碼
    system("PAUSE");
    return
#ifndef _MSC_VER
    EXIT_SUCCESS
#endif
    ;
}
```

#### WinMain

<image>

以微軟視窗為基礎的程式設計上，`WinMain`函式是視窗程式的進入點，函式原型如下所示：

```cpp
int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow);
```

### .Net 語言（C#、VB 等）

以C#編寫的程式，在開始執行時CLR會先去尋找帶有`.entrypoint` IL標示的靜態方法，而這個靜態方法可能沒有參數，或是只有單一`string[]`型態的參數，而且還有`void`或是`int`型態的傳回值，找到後才會執行這個方法，而這個方法就是主函式。

```csharp
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 方法來當做程式開始的起點，方法如下：

```java
public static void main(String[] args)
```

命令列指定參數是args。如同C和C++一樣，「main」也是唯一的。Java的main方法無任何的傳回值。

### Pascal

Pascal的主要程序是不需命名的。因為Pascal程式的程序和函式在編寫程式上比C、C++或是Java更加嚴格，在程式裡主要程序通常才是最後的程序。Pascal沒有main或是其他相類似的關鍵字。

以下是Hello world範例：

```pascal
procedure hello() begin
  writeln('Hello world')
end;
begin
  hello()
 end.
```

### Pike

Pike與C/C++的語法相類似。從main開始執行。「argc」代表環境參數的個數。「argv」代表環境參數的值。

舉例如下：

```java
int main(int argc, array(string) argv)
```

## 參見

- crt0，連接到C程序上的一組執行啟動例程。
- 運行時系統