来源:《周哥教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函数之后执行。

代码如下:

 #include <stdio.h>

 __attribute((constructor)) void before_main()
 {
     printf("before main!\n");
 }

 __attribute((destructor)) void after_main()
 {
     printf("after main!\n");
 }

 int main(void)
 {
     printf("This is main function.\n");
     ;
 }

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");
    ;
}

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");
    ;
}

before_main.c

3. C++编程中利用定义全局类对象or全局变量

mainCRTStartup会对全局对象a初始化,也就是说a的构造含税会先于main执行,所以只需要在a的构造函数中定义我们要执行的函数。

另一种方式是定义一个全局变量为函数运行后的结构,那么该函数就会用于初始化,会先于main执行。

代码如下:

 #include <iostream>
 using namespace std;
 using std::cout;

 int func()
 {
     cout <<"before main: func()" << endl;
     ;
 }

 class A
 {
 public:
     A()
     {
         cout << "A() constructor" << endl;
     }
     ~A()
     {
         cout << "A() destructor" << endl;
     }
 };

 A a;

 int g_iValue = func();

 int main(void)
 {
     cout << "This is main function." << endl;
     ;
 }

before_main.cpp

运行结果:

A() constructor
before main: func()
This is main function.
A() destructor

最新文章

  1. MVVM架构~knockoutjs系列之扩展ajax验证~验证数据是否存在
  2. 9patch边框黑线的含义
  3. 如何在真机上调试Android应用程序(图文详解)(zz)
  4. Unity中实现List类型的自定义GUI(ReorderableList)
  5. PHP使用empty检查函数返回结果时报Fatal error: Can&#39;t use function return value in write context的问题
  6. 笔记-iOS 视图控制器转场详解(上)
  7. 菜鸟学EJB(二)——在同一个SessionBean中使用@Remote和@Local
  8. PHP正则提取HTML中img的url值
  9. 结构体的vector resize()与初始化
  10. macaca 环境搭建篇,(web 和安卓)
  11. js-异步机制与同步机制
  12. Windows环境下springboot集成redis的安装与使用
  13. MVC4 发布到II7或者IIS7.5遇到NO Find问题
  14. nginx 环境不支持thinkPHP
  15. canvas 水波纹
  16. Redis须知重点
  17. 常用LINQ关键字用法汇总
  18. IOI2008 island
  19. BSGS-Junior&#183;大步小步算法
  20. 使用MapperScannerConfigurer简化MyBatis配置

热门文章

  1. form表单中enctype=&quot;multipart/form-data&quot;的传值问题
  2. Java比较器
  3. JavaScript 版数据结构与算法(一)栈
  4. apache、php隐藏http头部版本信息的实现方法
  5. python 发送邮件,未完
  6. cocos2dx - 控件扩展之pageview循环显示
  7. Android Annotations(2)
  8. Nodejs入门-基于Node.js的简单应用
  9. 反射型 DDoS 攻击的原理和防范措施
  10. pm2部署多个nodejs项目配置教程