最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網(wǎng) 會(huì)員登陸 & 注冊(cè)

C語(yǔ)言中這么騷的退出程序的方式你知道幾個(gè)?

2023-03-14 15:15 作者:程序員-王堅(jiān)  | 我要投稿

前言

在本篇文章當(dāng)中主要給大家介紹C語(yǔ)言當(dāng)中一些不常用的特性,比如在main函數(shù)之前和之后設(shè)置我們想要執(zhí)行的函數(shù),以及各種花式退出程序的方式。

main函數(shù)是最先執(zhí)行和最后執(zhí)行的函數(shù)嗎?

C語(yǔ)言構(gòu)造和析構(gòu)函數(shù)

通常我們?cè)趯?xiě)C程序的時(shí)候都是從main函數(shù)開(kāi)始寫(xiě),因此我們可能沒(méi)人有關(guān)心過(guò)這個(gè)問(wèn)題,事實(shí)上是main函數(shù)不是程序第一個(gè)執(zhí)行的函數(shù),也不是程序最后一個(gè)執(zhí)行的函數(shù)。

#include <stdio.h>void __attribute__((constructor)) init1() {printf("before main funciton\n");}int main() {printf("this is main funciton\n");}

我們編譯上面的代碼然后執(zhí)行,輸出結(jié)果如下圖所示:

? ?code git:(main) ./init.outbefore main funcitonthis is main funciton

由此可見(jiàn)main函數(shù)并不是第一個(gè)被執(zhí)行的函數(shù),那么程序第一次執(zhí)行的函數(shù)是什么呢?很簡(jiǎn)單我們看一下程序的調(diào)用棧即可。

從上面的結(jié)果可以知道,程序第一個(gè)執(zhí)行的函數(shù)是_start,這是在類(lèi)Unix操作系統(tǒng)上執(zhí)行的第一個(gè)函數(shù)。

那么main函數(shù)是程序執(zhí)行的最后一個(gè)函數(shù)嗎?我們看下面的代碼:

#include <stdio.h>void __attribute__((destructor)) __exit() {printf("this is exit\n");}void __attribute__((constructor)) init() {printf("this is init\n");}int main() {printf("this is main\n");return 0;}

上面程序的輸出結(jié)果如下:

? ?code git:(main) ./out.outthis is initthis is mainthis is exit

由此可見(jiàn)main函數(shù)也不是我們最后執(zhí)行的函數(shù)!事實(shí)上我們除了上面的方法之外我們也可以在libc當(dāng)中注冊(cè)一些函數(shù),讓程序在main函數(shù)之后,退出執(zhí)行前執(zhí)行這些函數(shù)。

on_exit和atexit函數(shù)

我們可以使用上面兩個(gè)函數(shù)進(jìn)行函數(shù)的注冊(cè),讓程序退出之前執(zhí)行我們指定的函數(shù)

#include <stdio.h>#include <stdlib.h>void __attribute__((destructor)) __exit() {printf("this is exit\n");}void __attribute__((constructor)) init() {printf("this is init\n");}void on__exit() {printf("this in on exit\n");}void at__exit() {printf("this in at exit\n");}int main() {on_exit(on__exit, NULL);atexit(at__exit);printf("this is main\n");return 0;}this is initthis is mainthis in at exitthis in on exitthis is exit

我們可以仔細(xì)分析一下上面程序執(zhí)行的順序。首先是執(zhí)構(gòu)造函數(shù),然后執(zhí)行 atexit 注冊(cè)的函數(shù),再執(zhí)行 on_exit 注冊(cè)的函數(shù),最后執(zhí)行析構(gòu)函數(shù)。從上面程序的輸出我們可以知道我們注冊(cè)的函數(shù)生效了,但是需要注意一個(gè)問(wèn)題,先注冊(cè)的函數(shù)后執(zhí)行,不管是使用 atexit 還是 on_exit 函數(shù)。我們現(xiàn)在看下面的代碼:

#include <stdio.h>#include <stdlib.h>void __attribute__((destructor)) __exit() {printf("this is exit\n");}void __attribute__((constructor)) init() {printf("this is init\n");}void on__exit() {printf("this in on exit\n");}void at__exit() {printf("this in at exit\n");}int main() {// 調(diào)換下面兩行的順序atexit(at__exit);on_exit(on__exit, NULL);printf("this is main\n");return 0;}

上面的代碼輸出如下:

this is initthis is mainthis in on exitthis in at exitthis is exit

從輸出的結(jié)果看確實(shí)和上面我們提到的規(guī)則一樣,先注冊(cè)的函數(shù)后執(zhí)行。這一點(diǎn)再linux程序員開(kāi)發(fā)手冊(cè)里面也提到了。

但是這里有一點(diǎn)需要注意的是我們應(yīng)該盡可能使用atexit函數(shù),而不是使用on_exit函數(shù),因?yàn)閍texit函數(shù)是標(biāo)準(zhǔn)規(guī)定的,而on_exit并不是標(biāo)準(zhǔn)規(guī)定的。

exit和_exit函數(shù)

其中exit函數(shù)是libc給我們提供的函數(shù),我們可以使用這個(gè)函數(shù)正常的終止程序的執(zhí)行,而且我們?cè)谇懊孀?cè)的函數(shù)還是能夠被執(zhí)行。比如在下面的代碼當(dāng)中:

#include <stdio.h>#include <stdlib.h>#include <unistd.h>void __attribute__((destructor)) __exit1() {printf("this is exit1\n");}void __attribute__((destructor)) __exit2() {printf("this is exit2\n");}void __attribute__((constructor)) init1() {printf("this is init1\n");}void __attribute__((constructor)) init2() {printf("this is init2\n");}void on__exit1() {printf("this in on exit1\n");}void at__exit1() {printf("this in at exit1\n");}void on__exit2() {printf("this in on exit2\n");}void at__exit2() {printf("this in at exit2\n");}int main() {// _exit(1);on_exit(on__exit1, NULL);on_exit(on__exit2, NULL);atexit(at__exit1);atexit(at__exit2);printf("this is main\n");exit(1);return 0;}

上面的函數(shù)執(zhí)行結(jié)果如下所示:

this is init1this is init2this is mainthis in at exit2this in at exit1this in on exit2this in on exit1this is exit2this is exit1

可以看到我們的代碼被正常執(zhí)行啦。

但是_exit是一個(gè)系統(tǒng)調(diào)用,當(dāng)執(zhí)行這個(gè)方法的時(shí)候程序會(huì)被直接終止,我們看下面的代碼:

#include <stdio.h>#include <stdlib.h>#include <unistd.h>void __attribute__((destructor)) __exit1() {printf("this is exit1\n");}void __attribute__((destructor)) __exit2() {printf("this is exit2\n");}void __attribute__((constructor)) init1() {printf("this is init1\n");}void __attribute__((constructor)) init2() {printf("this is init2\n");}void on__exit1() {printf("this in on exit1\n");}void at__exit1() {printf("this in at exit1\n");}void on__exit2() {printf("this in on exit2\n");}void at__exit2() {printf("this in at exit2\n");}int main() {// _exit(1);on_exit(on__exit1, NULL);on_exit(on__exit2, NULL);atexit(at__exit1);atexit(at__exit2);printf("this is main\n");_exit(1); // 只改了這個(gè)函數(shù) 從 exit 變成 _exitreturn 0;}

上面的代碼輸出結(jié)果如下所示:

this is init1this is init2this is main

可以看到我們注冊(cè)的函數(shù)和最終的析構(gòu)函數(shù)都沒(méi)有被執(zhí)行,程序直接退出啦。

花式退出

出了上面的_exit函數(shù)之外,我們還可以使用其他的方式直接退出程序:

#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <sys/syscall.h> void __attribute__((destructor)) __exit1() {printf("this is exit1\n");}void __attribute__((destructor)) __exit2() {printf("this is exit2\n");}void __attribute__((constructor)) init1() {printf("this is init1\n");}void __attribute__((constructor)) init2() {printf("this is init2\n");}void on__exit1() {printf("this in on exit1\n");}void at__exit1() {printf("this in at exit1\n");}void on__exit2() {printf("this in on exit2\n");}void at__exit2() {printf("this in at exit2\n");}int main() {// _exit(1);on_exit(on__exit1, NULL);on_exit(on__exit2, NULL);atexit(at__exit1);atexit(at__exit2);printf("this is main\n");syscall(SYS_exit, 1); // 和 _exit 效果一樣return 0;}

出了上面直接調(diào)用函數(shù)的方法退出函數(shù),我們還可以使用內(nèi)聯(lián)匯編退出函數(shù),比如在64位操作系統(tǒng)我們可以使用下面的代碼退出程序:

#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <sys/syscall.h> void __attribute__((destructor)) __exit1() {printf("this is exit1\n");}void __attribute__((destructor)) __exit2() {printf("this is exit2\n");}void __attribute__((constructor)) init1() {printf("this is init1\n");}void __attribute__((constructor)) init2() {printf("this is init2\n");}void on__exit1() {printf("this in on exit1\n");}void at__exit1() {printf("this in at exit1\n");}void on__exit2() {printf("this in on exit2\n");}void at__exit2() {printf("this in at exit2\n");}int main() {// _exit(1);on_exit(on__exit1, NULL);on_exit(on__exit2, NULL);atexit(at__exit1);atexit(at__exit2);printf("this is main\n");asm("movq $60, %%rax;""movq $1, %%rdi;""syscall;":::"eax");return 0;}

上面是在64位操作系統(tǒng)退出程序的匯編實(shí)現(xiàn),在64為系統(tǒng)上退出程序的系統(tǒng)調(diào)用號(hào)為60。下面我們使用32位操作系統(tǒng)上的匯編實(shí)現(xiàn)程序退出,在32位系統(tǒng)上退出程序的系統(tǒng)調(diào)用號(hào)等于1:

#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <sys/syscall.h>void __attribute__((destructor)) __exit1() {printf("this is exit1\n");}void __attribute__((destructor)) __exit2() {printf("this is exit2\n");}void __attribute__((constructor)) init1() {printf("this is init1\n");}void __attribute__((constructor)) init2() {printf("this is init2\n");}void on__exit1() {printf("this in on exit1\n");}void at__exit1() {printf("this in at exit1\n");}void on__exit2() {printf("this in on exit2\n");}void at__exit2() {printf("this in at exit2\n");}int main() {// _exit(1);on_exit(on__exit1, NULL);on_exit(on__exit2, NULL);atexit(at__exit1);atexit(at__exit2);printf("this is main\n");asm volatile("movl $1, %%eax;""movl $1, %%edi;""int $0x80;":::"eax");return 0;}

總結(jié)

在本篇文章當(dāng)中主要給大家介紹C語(yǔ)言當(dāng)中一些與程序退出的騷操作,希望大家有所收獲!


C語(yǔ)言中這么騷的退出程序的方式你知道幾個(gè)?的評(píng)論 (共 條)

分享到微博請(qǐng)遵守國(guó)家法律
大理市| 五指山市| 洛浦县| 襄樊市| 三江| 乐业县| 承德县| 祁连县| 汉阴县| 沙湾县| 宜君县| 梁河县| 玛纳斯县| 抚宁县| 迁安市| 巴彦淖尔市| 达州市| 酒泉市| 遂宁市| 阿鲁科尔沁旗| 成武县| 定安县| 平阴县| 和平区| 保定市| 枣阳市| 桐乡市| 霞浦县| 和田县| 铁岭县| 兴义市| 蒲城县| 新龙县| 新昌县| 凤山市| 香河县| 莲花县| 博客| 友谊县| 宁津县| 广州市|