前几天为新员工写一个简单的测试框架,可让他们方便的写测试用例并且执行。期间遇到一个问题就是如何让他们增加测试用例而用不影响测试框架的代码?c++的单件模式可以解决这个问题,但是其中一个难点是要在main之前注册单件。c++可以通过构造函数来实现注册,c如何注册?
最后查了下资料,原来可以定义在main之前调用的函数!有了这个特性可以改善c的模块化设计。
特性介绍:
如果想定义在main函数之前调用的函数,可以在函数的声明之后加上一句“__attribute__((constructor))”,如下:
intbefore()__attribute__((constructor));
如果想定义在main函数之后调用的函数,可以在函数的声明之后加上一句“__attribute__((destructor))”,如下:
intafter()__attribute__((destructor));
可以看得出来,应该类似于c++中的构造和析构。
一些细节问题:
写测试代码测试了一下这个程序,发现几点:
1、before在main之前调用,调用之前,各个全局变量已经完成初始化。也就是说,这些函数是在全局变量初始化之后,main函数之前调用的。这一点是非常重要的,否则可能会引起很多的问题。
2、after在main之后调用,但是有一点比较特殊,必须是在main中return的话才执行,否则,需要通过atexit执行某函数。这个特性目前对我没有太大的用处。
3、在main函数之前调用的函数可以声明为static。
4、在main函数之前调用的函数可以调用多个。这里就有一个问题,就是这些函数的调用顺序的问题。这个问题首先是一个设计的问题,也就是,我们应该设计这些函数为顺序无关的函数。另外,调用顺序和编译的顺序相关,我在linux下使用make进行编译,发现最后编译的源文件中的函数会最先调用。
5、可以在库(动态库和静态库)中定义这样的函数。
用对设计的作用:
1、可以优化c++中的单件模式。参考《设计模式》
单件模式有一个最大的特点就是可以在运行过程中连接单件。如果使用条件语句来决定使用哪个单件硬性限定了可能的单件集合。所以,书中引入了一个单件注册表的概念,书中对单件注册表的初始化采用的是如下的做法:
首先定义一个单件类,在单件类的构造函数中调用单件的注册函数注册自身:
这个函数是怎么被调用的那?可以定义一个静态实例:
staticMySingletontheSingleton;
这样就会在main函数之前调用MySingleton的构造函数来构造这个静态实例,从而达到像注册表注册的目的。
这个方案有个缺点:它能够成功存在一个前提,就是在theSingleton实例化之前,单件注册表列表必须存在,否则会失败。则其实只是一个可能失败的点,如果MySingleton还应用其他的全局变量,则可能这个时候这些全局变量还没有初始化。
解决这个问题的一个方案就是将单件注册的时间由构造函数移到main函数之前调用的函数中来。
定义函数:
before_main会在main函数之前调用,而调用时全局变量已经全部初始化,这样就可以避免上面的问题。
其实单件不单单可以在c++(面向对象)中使用,也可以在c中使用。而且有了c的这个特性后,单件更好用。
2、构造插件开发框架,而不用对框架进行更改。
构造插件开发框架的一个问题是:如何新增一个插件而不用修改主框架代码就可以调用插件代码。一般情况下都会使用插件注册机制。也就是框架对外提供注册接口,插件使用这些接口进行注册。c要实行此功能,一个可行的方案是在插件中定义main之前执行的函数,在此函数中调用插件注册接口完成注册。(注:这里讨论的是插件的静态加载)。
3、一个模块有一些初始化工作要做,使用这种机制可以不更改main或者函数。
抛开插件框架,使用这个特性也可以对c的模块化进行很多优化。比如,可以把各个模块的初始化工作放在main之前进行从而防止对main的频繁修改。
注:本文描述的环境为linuxc,c++。
分享到:
相关推荐
在main函数之前调用函数,以及对设计的作用.pdf
前几天为新员工写一个简单的...特性介绍:如果想定义在main函数之前调用的函数,可以在函数的声明之后加上一句“__attribute__((constructor))”,如下:int before()__attribute__((constructor));如果想定义在main
一般在Python中在函数中定义的函数是不能直接调用的,但是如果要用的话怎么办呢? 一般情况下: def a():#第一层函数 def b():#第二层函数 print('打开文件B') b()#第二层中的函数直接调用 结果显示: Traceback...
在main函数传值调用
C语言程序设计-从键盘为一维整型数组输入10个整数,调用fun函数找出其中最小的数,并在main函数中输出;本.cC语言程序设计-
详细介绍了main函数如何调用子函数的过程,非常的经典
C语言程序设计-调用函数fun判断一个三位数是否水仙花数;在main函数中从键盘输入一个三位数,并输出判断结果;请编写fun函数;说明:所谓水仙花数是指一3位数,其各位数字立方和等于该数本身;例如:153是一个水仙花数,...
C语言程序设计-从键盘输入一个大于3的整数,调用函数fun判断其是否素数,然后在main函数中输出相应的结论信息;例如:7是素数,8不是素数;请编写fun函数;素数是仅能被1和自身整除的数.c
C语言程序设计-从键盘为一维整型数组输入10个整数,调用fun函数找出其中最小的数,并在main函数中输出;请编写fun函数;.c
C语言编程-编写函数fun求一个字符串的长度,在main函数中输入字符串,并输出其长度;
C语言程序设计-编写main程序调用函数fact求解从m个元素选n个元素的组合数的个数;计算公式是: 组合数=m!(n!.(m-n)!);要求m不能小于n,否则应有容错处理;说明:函数fact(x)的功能是求x!;
主要介绍了Android studio 运行main 函数的方法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
C语言程序设计-编写函数fun将一个数组中的值按逆序存放,并在main()函数中输出;例如:原来存顺序为8,6,5,4,1;要求改为:1,4,5,6,8;.c
C语言编程-编写函数fun求1!+2!+3!+ …… +n!的和,在main函数中由键盘输入n值,并输出运算结果;请编写fun函数;例如:若n值为5,则结果为153;
C语言程序设计-编写函数实现两个数据的交换,在主函数中输入任意三个数据,调用函数对这三个数据从大到小排序;.c
本程序是完整的项目文件,在VS2008下运行成功,程序功能:通过传递主窗体句柄,然后打开子窗体,在子窗体中可对主窗体的控件或函数进行操作,改变其控件属性 ,调用主窗体的函数,(注:在调用前要修改主窗体被调用控件或函数...
为初学者提供的资源 ,建议大家看看 ... static void Main() { Console.WriteLine("write the arry'length"); int i=1; while (i > 0) { i = Int32.Parse(Console.ReadLine()); PrintArr(i); } } }
刚写完,是一道作业题,想试试主函数递归,所以写了出来,给大家看看,初学C……希望大家指教