C语言退出程序的方法你知道多少?前言在这篇文章中,我们主要介绍一些C语言中不常见的特性,比如在main函数前后设置我们要执行的函数,以及各种花哨的程序退出方式。main函数是第一个也是最后一个要执行的函数吗?C语言的构造函数和析构函数,我们写C程序的时候一般都是从main函数开始的,所以我们可能没有人关心过这个问题。其实main函数并不是程序执行的第一个函数,也不是程序执行的最后一个函数。#includevoid__attribute__((constructor))init1(){printf("beforemainfunciton\n");}intmain(){printf("thisismainfunciton\n");}我们编译然后执行上面的代码,输出结果如下图所示:?codegit:(main)./init.outbeforemainfuncitonthisismainfunciton可以看出main函数不是第一个函数被执行,那么程序首先执行的函数是什么?这很简单。我们来看看程序的调用栈。[]从上面的结果我们可以知道程序执行的第一个函数是_start,这是类Unix操作系统上执行的第一个函数。那么main函数是程序执行的最后一个函数吗?让我们看看下面的代码:#includevoid__attribute__((destructor))__exit(){printf("thisisexit\n");}void__attribute__((constructor))init(){printf("这是init\n");}intmain(){printf("这是main\n");return0;}上面程序的输出结果如下:?codegit:(main)./out.outthisisinitthisismainthisisexit可见main函数并不是我们执行的最后一个函数!其实除了上面的方法,我们还可以在libc中注册一些函数,让程序在main函数之后,退出执行之前执行这些函数。on_exit和atexit函数我们可以使用上面两个函数来注册函数,让程序在退出前执行我们指定的函数#include#includevoid__attribute__((destructor))__exit(){printf("thisisexit\n");}void__attribute__((constructor))init(){printf("thisisinit\n");}voidon__exit(){printf("thisinonexit\n");}voidat__exit(){printf("thisinatexit\n");}intmain(){on_exit(on__exit,NULL);atexit(at__exit);printf("这是主要的\n");return0;}thisisinitthisismainthisinatexitthisinonexitthisisexit我们可以仔细分析上面程序的执行顺序。首先执行构造函数,然后执行atexit注册的函数,再执行on_exit注册的函数,最后执行析构函数。从上面程序的输出我们可以知道我们注册的函数已经生效了,但是需要注意一个问题,先注册的函数会先执行,不管是使用atexit还是on_exit函数.现在让我们看一下下面的代码:#include#includevoid__attribute__((destructor))__exit(){printf("thisisexit\n");}void__attribute__((constructor))init(){printf("thisisinit\n");}voidon__exit(){printf("thisinonexit\n");}voidat__exit(){printf("thisinatexit\n");}intmain(){//颠倒下面两行的顺序atexit(at__exit);on_exit(on__exit,NULL);printf("这是主要的\n");return0;}上面代码的输出结果如下:thisisinitthisismainthisinonexitthisinatexitthisisexit从输出结果来看,确实和我们上面说的规则一样,先注册函数然后然后执行。这一点在《Linux程序员开发手册》中也有提到。但是这里要注意一点,我们应该尽量使用atexit函数,而不是on_exit函数,因为atexit函数是标准规定的,而on_exit是标准没有规定的。exit和_exit函数exit函数是libc提供的函数。我们可以使用这个函数来正常终止程序的执行,而我们之前注册的函数仍然可以执行。比如下面的代码当场:#include#include#includevoid__attribute__((destructor))__exit1(){printf("thisisexit1\n");}void__attribute__((destructor))__exit2(){printf("这是exit2\n");}void__attribute__((constructor))init1(){printf("这是init1\n");}void__attribute__((构造函数))init2(){printf("这是init2\n");}voidon__exit1(){printf("thisinonexit1\n");}voidat__exit1(){printf("thisinatexit1\n");}voidon__exit2(){printf("thisinonexit2\n");}voidat__exit2(){printf("thisinatexit2\n");}intmain(){//_exit(1);on_exit(on__exit1,NULL);on_exit(on__exit2,NULL);atexit(at__exit1);atexit(at__exit2);printf("这是主要的\n");退出(1);return0;}上面的函数执行结果如下所示:thisisinit1thisisinit2thisismainthisinatexit2thisinatexit1thisinonexit2thisinonexit1thisisexit2thisisexit1可以看到我们的代码正常执行了但是_exit是一个系统调用。当执行该方法时,程序将直接终止。让我们看一下下面的代码:}void__attribute__((destructor))__exit2(){printf("这是exit2\n");}void__attribute__((constructor))init1(){printf("这是init1\n");}void__attribute__((constructor))init2(){printf("thisisinit2\n");}voidon__exit1(){printf("thisinonexit1\n");}voidat__exit1(){printf("thisinatexit1\n");}voidon__exit2(){printf("thisinonexit2\n");}voidat__exit2(){printf("thisinatexit2\n");}intmain(){//_exit(1);on_exit(on__exit1,NULL);on_exit(on__exit2,NULL);atexit(at__exit1);atexit(at__exit2);printf("这是主要的\n");_退出(1);//只是把这个函数从exit改成了_exitreturn0;}上面代码的输出结果如下:thisisinit1thisisinit2thisismain你可以看到我们注册的函数和final一个析构函数都不执行,程序直接退出。花式退出除了上面的_exit函数,我们还可以使用其他方法直接退出程序:#include#include#include#includevoid__attribute__((destructor))__exit1(){printf("这是exit1\n");}void__attribute__((destructor))__exit2(){printf("这是exit2\n");}void__attribute__((constructor))init1(){printf("这是init1\n");}void__attribute__((constructor))init2(){printf("这是init2\n");}voidon__exit1(){printf("thisinonexit1\n");}voidat__exit1(){printf("thisinatexit1\n");}voidon__exit2(){printf("thisinonexit2\n");}voidat__exit2(){printf("thisinatexit2\n");}intmain(){//_exit(1);on_exit(on__exit1,NULL);on_exit(on__exit2,NULL);atexit(at__exit1);atexit(at__exit2);printf("这是主要的\n");系统调用(SYS_exit,1);//效果同_exitreturn0;}exit上面直接调用函数的方法,我们也可以使用inlineAssemblyexit函数,比如在64位操作系统我们可以使用下面的代码退出程序:#include#include#include#includevoid__attribute__((destructor))__exit1(){printf("这是exit1\n");}void__attribute__((析构函数))__exit2(){printf("这是exit2\n");}void__attribute__((构造函数))init1(){printf("thisisinit1\n");}void__attribute__((constructor))init2(){printf("thisisinit2\n");}voidon__exit1(){printf("thisinonexit1\n");}voidat__exit1(){printf("thisinatexit1\n");}voidon__exit2(){printf("thisinonexit2\n");}voidat__exit2(){printf("thisinatexit2\n");}intmain(){//_exit(1);on_exit(on__exit1,NULL);on_exit(on__exit2,NULL);atexit(at__exit1);atexit(at__exit2);printf("这是主要的\n");asm("movq$60,%%rax;""movq$1,%%rdi;""系统调用;":::"eax");return0;}以上是exit程序在64位操作系统的汇编实现,64位系统退出程序的系统调用号为60下面我们使用32位操作系统上的程序集来实现程序退出。32位系统上exit程序的系统调用号等于1:#include#include#include#includevoid__attribute__((析构函数))__exit1(){printf("这是exit1\n");}void__attribute__((destructor))__exit2(){printf("这是exit2\n"");}void__attribute__((constructor))init1(){printf("这是init1\n");}void__attribute__((constructor))init2(){printf("这是init2\n");}voidon__exit1(){printf("thisinonexit1\n");}voidat__exit1(){printf("thisinatexit1\n");}voidon__exit2(){printf("thisinonexit2\n"");}voidat__exit2(){printf("thisinatexit2\n");}intmain(){//_exit(1);on_exit(on__exit1,NULL);on_exit(on__exit2,NULL);atexit(at__exit1);atexit(at__exit2);printf("这是主要的\n");asmvolatile("movl$1,%%eax;""movl$1,%%edi;""int$0x80;"::::"eax");return0;}小结本文主要介绍C语言的一些操作和程序退出,希望大家有所收获!以上就是本文的全部内容文章内容到此结束,我是LeHung,下期再见!!!更多精彩内容合集可访问:https://github.com/Chang-LeHu...关注公众号:好-白学僧,了解更多计算机(Java、Python、计算机系统基础、算法与数据结构)知识