標籤:完成 names after 全域 -o 記憶體 nat 初始化 結構
來源:《周哥教IT.C語言深學活用》https://ke.qq.com/course/242707#tuin=a71606
我們在學習C/C++語言的時候,通常認為main函數是整個程式執行的開始。實際上,在main函數之前,會有一系列初始化的操作,這樣的操作通常是由連結器等完成的。具體說來,程式最早執行的函數其實並不是main,在windows中,是mainCRTStartup,這個函數是連結器執行以初始化執行階段程式庫的,此函數又會調用CRTInit函數,該函數會對C全域變數、C記憶體配置以及C++中的全域類對象和建構函式進行初始化工作。所以想要在main函數之前執行一些自己的代碼,是有可能的。
1. Linux環境下利用gcc的__attribute關鍵字
在Linux環境的C編程中,可以利用__attribute關鍵字定義constructor和destructor,其中前者會在main函數之前執行,後者會在main函數之後執行。
代碼如下:
1 #include <stdio.h> 2 3 __attribute((constructor)) void before_main() 4 { 5 printf("before main!\n"); 6 } 7 8 __attribute((destructor)) void after_main() 9 {10 printf("after main!\n");11 }12 13 int main(void)14 {15 printf("This is main function.\n");16 return 0;17 }before_main.c
運行結果:
[email protected]:~/Desktop/zhou_it_c/before_main$ gcc before_main.c -o before_main
[email protected]:~/Desktop/zhou_it_c/before_main$ ./before_main
before main!
This is main function.
after main!
2. Windows環境下利用#pragma預定義
上面我們說過CRTInit函數中會做一些初始化工作,包括C庫、C的初始化函數、C++庫、C++的初始化函數等。C和C++分別有一張表來儲存初始化函數指標,每個表又會使用2個指標來明確範圍。在初始化過程中,__CRTInit函數會一次調用這兩個表中的函數,所以如果我們能把要執行的函數放在這兩個表中,那麼就可以達到在main之前執行代碼的目的了。
C初始化函數表的範圍是:[ __xi_a, __xi_a ] C++初始化函數表的範圍是:[ __xc_a, __xc_z]
我們在具體執行的時候,通過定義特殊的段名稱“.CRT$XIU”和“.CRT$XCU”,把要執行的函數放在段中。連結器就會形成日下的C初始化函數表:
[__xi_a, ..., before1(xiu), ..., __xi_z]
以及C++初始化函數表:
[__xc_a, ..., before2(xcu), ..., __xc_z]
代碼如下:
#include <stdio.h>int before_main(void){ printf("before main!\n"); return 0;}typedef int func();#pragma data_seg(".CRT$XIU")static func *before[] = { before_main };#pragma data_seg()int main(void){ printf("This is main function.\n"); return 0;}before_main.c
3. C++編程中利用定義全域類對象or全域變數
mainCRTStartup會對全域對象a初始化,也就是說a的構造含稅會先於main執行,所以只需要在a的建構函式中定義我們要執行的函數。
另一種方式是定義一個全域變數為函數運行後的結構,那麼該函數就會用於初始化,會先於main執行。
代碼如下:
1 #include <iostream> 2 using namespace std; 3 using std::cout; 4 5 int func() 6 { 7 cout <<"before main: func()" << endl; 8 return 0; 9 }10 11 class A12 {13 public:14 A()15 {16 cout << "A() constructor" << endl;17 }18 ~A()19 {20 cout << "A() destructor" << endl;21 }22 };23 24 A a;25 26 int g_iValue = func();27 28 int main(void)29 {30 cout << "This is main function." << endl;31 return 0;32 }before_main.cpp
運行結果:
A() constructor
before main: func()
This is main function.
A() destructor
C/C++程式在main之前執行代碼