入口点

<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程序上的一组执行启动例程。
- 运行时系统