亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

C語(yǔ)言中花式退出程序的方式總結(jié)

 更新時(shí)間:2022年10月19日 08:14:18   作者:一無(wú)是處的研究僧  
在本篇文章當(dāng)中主要給大家介紹C語(yǔ)言當(dāng)中一些不常用的特性,比如在main函數(shù)之前和之后設(shè)置我們想要執(zhí)行的函數(shù),以及各種花式退出程序的方式,需要的可以參考一下

前言

在本篇文章當(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.out 
before main funciton
this 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.out 
this is init
this is main
this 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 init
this is main
this in at exit
this in on exit
this 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 init
this is main
this in on exit
this in at exit
this 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 init1
this is init2
this is main
this in at exit2
this in at exit1
this in on exit2
this in on exit1
this is exit2
this 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 變成 _exit
  return 0;
}

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

this is init1
this is init2
this 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;
}

以上就是C語(yǔ)言中花式退出程序的方式總結(jié)的詳細(xì)內(nèi)容,更多關(guān)于C語(yǔ)言退出程序的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • C++使用郵件槽實(shí)現(xiàn)ShellCode跨進(jìn)程傳輸

    C++使用郵件槽實(shí)現(xiàn)ShellCode跨進(jìn)程傳輸

    在計(jì)算機(jī)安全領(lǐng)域,進(jìn)程間通信(IPC)一直是一個(gè)備受關(guān)注的話題,在本文中,我們將探討如何使用Windows郵件槽(Mailslot)實(shí)現(xiàn)ShellCode的跨進(jìn)程傳輸,需要的可以參考下
    2023-12-12
  • 詳解C/C++ Linux出錯(cuò)處理函數(shù)(strerror與perror)的使用

    詳解C/C++ Linux出錯(cuò)處理函數(shù)(strerror與perror)的使用

    我們知道,系統(tǒng)函數(shù)調(diào)用不能保證每次都成功,必須進(jìn)行出錯(cuò)處理,這樣一方面可以保證程序邏輯正常,另一方面可以迅速得到故障信息。本文主要為大家介紹兩個(gè)出錯(cuò)處理函數(shù)(strerror、perror)的使用,需要的可以參考一下
    2023-01-01
  • C語(yǔ)言strtod()函數(shù)案例詳解

    C語(yǔ)言strtod()函數(shù)案例詳解

    這篇文章主要介紹了C語(yǔ)言strtod()函數(shù)案例詳解,本篇文章通過(guò)簡(jiǎn)要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下
    2021-07-07
  • Linux網(wǎng)絡(luò)編程之UDP Socket程序示例

    Linux網(wǎng)絡(luò)編程之UDP Socket程序示例

    這篇文章主要介紹了Linux網(wǎng)絡(luò)編程之UDP Socket程序示例,有助于讀者在實(shí)踐中掌握UDP協(xié)議的原理及應(yīng)用方法,需要的朋友可以參考下
    2014-08-08
  • C語(yǔ)言細(xì)致講解線程同步的集中方式

    C語(yǔ)言細(xì)致講解線程同步的集中方式

    多線程中的線程同步可以使用,CreateThread,CreateMutex 互斥鎖實(shí)現(xiàn)線程同步,通過(guò)臨界區(qū)實(shí)現(xiàn)線程同步,Semaphore 基于信號(hào)實(shí)現(xiàn)線程同步,CreateEvent 事件對(duì)象的同步,以及線程函數(shù)傳遞單一參數(shù)與多個(gè)參數(shù)的實(shí)現(xiàn)方式
    2022-05-05
  • 探討:用兩個(gè)棧實(shí)現(xiàn)一個(gè)隊(duì)列(我作為面試官的小結(jié))

    探討:用兩個(gè)棧實(shí)現(xiàn)一個(gè)隊(duì)列(我作為面試官的小結(jié))

    作為面試官的我,經(jīng)常拿這道用兩個(gè)棧實(shí)現(xiàn)一個(gè)隊(duì)列的面試題來(lái)考面試者,通過(guò)對(duì)面試者的表現(xiàn)和反應(yīng),有一些統(tǒng)計(jì)和感受,在此做個(gè)小結(jié)
    2013-05-05
  • C++中使用function和bind綁定類(lèi)成員函數(shù)的方法詳解

    C++中使用function和bind綁定類(lèi)成員函數(shù)的方法詳解

    這篇文章主要介紹了C++中使用function和bind綁定類(lèi)成員函數(shù)的方法,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-11-11
  • C++ 純虛函數(shù)詳解

    C++ 純虛函數(shù)詳解

    本文主要介紹了C++ 純虛函數(shù)詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-09-09
  • Cocos2d-x保存用戶(hù)游戲數(shù)據(jù)之XML文件是否存在問(wèn)題判斷方法

    Cocos2d-x保存用戶(hù)游戲數(shù)據(jù)之XML文件是否存在問(wèn)題判斷方法

    這篇文章主要介紹了Cocos2d-x保存用戶(hù)游戲數(shù)據(jù)之XML文件是否存在問(wèn)題判斷方法,請(qǐng)注意代碼中包含大量注釋,需要的朋友可以參考下
    2014-09-09
  • 帶你分分鐘玩轉(zhuǎn)C語(yǔ)言指針

    帶你分分鐘玩轉(zhuǎn)C語(yǔ)言指針

    c語(yǔ)言指針其實(shí)是一個(gè)整形變量,與其它數(shù)據(jù)不同的是,它的作用是用來(lái)存儲(chǔ)其它變量的地址,下面這篇文章主要給大家介紹了關(guān)于C語(yǔ)言指針的相關(guān)資料,需要的朋友可以參考下
    2022-06-06

最新評(píng)論