1. 程式人生 > >C/C++程序在main之前執行代碼

C/C++程序在main之前執行代碼

val 構造 tar desktop log cto pen con ace

來源:《周哥教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

運行結果:

natalie@ubuntu:~/Desktop/zhou_it_c/before_main$ gcc before_main.c -o before_main

natalie@ubuntu:~/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 A
12 {
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之前執行代碼