入口点

本页使用了标题或全文手工转换,现处于中国大陆简体模式
求闻百科,共笔求闻
C#中主函数的例子。
C#源代码中Main()的样子。标记了不同部分用于参考。

计算机编程中,入口点是在程序中执行第一条指令的地方,和程序访问命令行参数的地方。要开始一个程序的执行装载器操作系统会将控制权传递到它的入口点。(在引导期间,操作系统自身就是这个程序)。这标志着从装载时(和动态连接时,如果存在的话)到运行时的转变。

对于某些操作系统和编程语言,入口点是运行时库,它是一组对语言的支持函数。库代码初始化程序并且接着把控制权传递给程序本身。在其他情况下,程序自身可以初始化运行时库。在简单的系统中,执行开始于第一条语句,这常见于解释型语言,简单的可执行格式,和引导装载器中。在其他情况下,入口点是在某个其他已知内存地址,这可以是绝对地址或相对地址(偏移量)。

可作为替代选择,程序的执行可以开始于命名点,要么是编程语言或操作系统定义的约定名字,要么是调用者指定的名字。在很多C家族语言中,这是叫做main的函数;作为结果,入口点经常叫做主函数。在JVM语言比如Java中,入口点是叫做main的静态方法;在CLI语言比如C#中,入口点是叫做Main的静态方法[1]

用法

在现代的计算机体系中,CPU 下一次要执行的指令地址由一个寄存器指出,称为“指令指针”(Instruction Pointer、IP)或“程序计数器”(Program Counter、PC)。该寄存器在系统上电或复位时由硬件电路置为某地址值,位于该地址的程序即可视为整个程序的入口点。这个概念一般只在嵌入式程序(固件)或操作系统的引导代码中使用,因为给非嵌入式系统写的程序通常包含数量庞大的机器指令、以至于关注一两个机器指令是没有意义的。

而所谓的“可执行”,说白了就是这个文件存储了一些信息、好创造某个让程序可以开始运行的内存状态,而操作系统装载并创建进程的步骤就是把这个满是机器指令的内存状态复原出来并开始运行。因此,可执行文件中的“程序入口点”表示把加载进来的哪个地址当作“开始运行”的那一条指令。

编程语言

C/C++

C语言C++编程语言,main的函数原型如下所示:

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

main的两个环境参数:argcargument count)与argvargument vector[2],两者个别自程序的指令列给予参数的数量与参数数组的指针地址。argcargv这两个参数的名称,在编程语言的命名规则底下,虽然可以依照用户的喜好自行定义,但是一般在使用上,还是会以现有的名称argcargv来进行程序的编写。其他具有相依平台的格式也可以被C与C++标准所接受;例如,UNIX(非POSIX.1)与Microsoft Visual C++有第三个参数,是用来接收程序的环境变量,利用其他方法访问环境变量,可以使用stdlib.h头文件定义的getenv函数:

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

Mac OS XApple Darwin有第四个参数,它含有操作系统支持性的信息,例如执行二进制文件的路径:

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的代码。

微软视窗为基础的程序设计上,WinMain[3]函数是视窗程序的进入点,函数原型如下所示:

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

.Net 语言(C#、VB 等)

C#编写的程序,在开始执行时CLR会先去查找带有.entrypoint IL标示的静态方法,而这个静态方法可能没有参数,或是只有单一string[]类型的参数,而且还有void或是int类型的传回值,找到后才会执行这个方法,而这个方法就是主函数。[4]

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.

Pike

Pike与C/C++的语法相类似。从main开始执行。“argc”代表环境参数的个数。“argv”代表环境参数的值。

举例如下:

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

参见

参考资料

  1. Wagner, Bill. Main() / Entry Points (C# Programming Guide) - Microsoft Developer Network. docs.microsoft.com. 2017-08-01 [2018-12-03] (美国英语). 
  2. argv: the vector term in this variable's name is used in traditional sense to refer to strings.(基本上这个参数是以传统的方法对参数的字符串进行访问的动作,相当于指针数组)
  3. 存档副本. [2009-10-28]. 
  4. 存档副本. [2009-11-04]. 

外部链接