前言:一篇好文章的诞生,需要你不断地搜集资料、整理思路,本站小编为你收集了丰富的c语言函数主题范文,仅供参考,欢迎阅读并收藏。
指导教师:__________ 成绩:__________
实验四 函数
一、 实验目的
1、掌握函数定义、调用和声明的方法
2、掌握实参和形参之间的传递方式
3、函数的嵌套调用
二、 实验内容
1、 写一个函数,将两个字符串连接。(习题8.6)
2、 编写一个函数,由实参传来一个字符串,统计此字符串中字母、数字、空格和其他字符的个数,在主函数中输入字符串以及输出上述的结果。(习题8.9)
3、 请将实验三中的实验内容三改正后,再改写成函数形式(排序部分)。
物理实验报告 ·化学实验报告 ·生物实验报告 ·实验报告格式 ·实验报告模板
关键词 多态性;面向对象;函数重载;运算符重载
中图分类号TP39 文献标识码A 文章编号 1674-6708(2011)40-0196-02
0 引言
多态性是面向对象程序设计的重要特征之一,它与封装性和继承性共同组成面向对象的程序设计的三大基本特征,在函数重载中,同一个函数名可对应若干种不同的实现,依据函数参数的类型、个数和顺序来确定某个实现。在运算符重载中,同一个运算符对应着很多种功能,这些功能是通过函数来定义的,依据操作数的类型来确定应选运算符的功能。我们接触的还有另一种是指同样的消息被不同类的对象接受时产生完全不同的实现,该情况大多产生在多类继承中不同类中的相同说明的成员函数的多态行为。其中多态性分为专用多态和通用多态,专用多态分为强制多态和重载多态;通用多态分为参数多态和包含多态。其中重载是实现C++多态性的一种十分重要的机制,成为重载多态,即为程序正文中相同作用域内的同一个标识符赋予不同的操作语义,实质上就是实现了程序空间到代码空间的一对多映射。
1 函数重载
简单地说函数重载就是赋给同一个函数名多个含义。在我们学的C++中函数重载分为普通函数的重载和成员函数的重载,也就是说我们所学的函数重载可以以两种不同的方式来实现,就是我们所说的普通函数的重载和成员函数的重载。
1.1 普通函数的重载
例1:
#include
float min(float x,float y){return x>y?x:y;}//求2个浮点型小数的最小值
float min(float x,float y,float z) {return x>y?(x>z?x:z):(y>z?y:z);}
//求3个浮点型小数的最小值
void main( )
{
cout
}
运行的结果:1.2,3.2
上一例题中,两个函数都是普通的函数重载,由于主函数中调用的两个函数对应的参数个数不同,所以通过形参和实参的结合,我们得到了运行的结果。
1.2 成员函数的重载
例2:
#include
class A
{
public:
A( ): a(0){cout
A(int x): a(x){cout
private:int a;
};
void main( )
{ A a1,a2(3); }
运行结果为: Default Constructing 0
Constructing 3
这是一个很常见的习题,该函数调用了构造函数的两种形式,有参和无参,对应于主函数中带有不同形式参数的函数,我们得到不同的结果。
2 运算符重载
运算符重载就是就是赋予已有的运算符多重含义,即多种功能。C++语言中通过重新定义运算符,使它能够用于特定类的对象执行的特定的功能。一般情况下运算符重载有两种形式,重载为类的成员函数和重载为有元函数两种。
2.1 重载为类的成员函数
例1:
#include
class complex
{
Public:complex(){real=imag=0;}
complex(double r,double i){real=r;imag=I;}
complex operator +(const complex &c);
complex operator -(const complex &c);
friend void print(const complex &c);
Private:double real,imag;
};
inline complex complex::operator +(const complex &c)
{return complex (real+c.rael,imag+c.imag);}
inline complex complex::operator -(const complex &c)
{return complex (real-c.rael,imag-c.imag);}
void print (const complex &c);
{
if (c.imag
cout
else
cout
}
void main()
{
complex c1(2.0,3.0),c2(4.0,-2.0),c3;
c3=c1+c2;
print(c3);
cout
c3=c1-c2;
cout
print(c3);
}
执行该程序的输出结果:
c1+c2=6+1i;
c1-c2=-2+5i;
2.2 重载为有元函数
执行的结果同例1,两种运算符比较,我们知道单目运算符最好被重载为成员函数,双目运算符最好被重载为有元函数。
3 结论
以上我们总结了函数重载和运算符重载的区别和特点。众所周知,重载是为了以不同的方式来实现函数,我们如果熟练的应用这门技术,可以提高程序的运行效率和可读性,通过学习,使我们更透彻地理解了C++的多态性问题。
参考文献
[1]谭浩强.C语言程序设计[M].3版.北京:清华大学出版社,2005,8.
[关键词]Java JNT C DLL
在现今的软件开发领域中,Java以其跨平台的优势得到大量的应用,其代码可以一次编译多处执行。但这种特性给Java带来了一定的局限性,幸好Java提供了完备的C/C++语言接口,这样我们可以利用C语言的强大功能实现Java难以实现的功能,在一定程序上消除Java的局限性和低效率。
一、创建DLL文件
使用某一种C/C++开发工具创建Dll文件,实现某一功能,供JAVA调用,例如本文在此使用Visual studio 2005创建一个名为testdll的动态库文件。
二、使用JNI
JNI是Java Native Interface的缩写,中文为JAVA本地调用。它允许Java代码和其他语言写的代码进行交互。
1.JAVA类
在JAVA程序中,首先需要在类中声明所调用的库名称,如下:
static {
System.loadLibrary(“testdll”); //加载动态库,testdll为DLL文件名称
}
还需要对将要调用的方法做本地声明,关键字为native。并且只需要声明,而不需要具体实现。如下:
public native static void set(int i);
public native static int get();
然后编译该JAVA程序文件,生成CLASS,再用JAVAH命令,JNI就会生成C/C++的头文件。
例如程序testdll.java,内容为:
public class testdll { static { System.loadLibrary(“testdll”); } public native static int get(); public native static void set(int i); public static void main(String[] args) { testdll test = new testdll(); test.set(10); System.out.println(test.get()); } }
用javac testdll.java编译它,会生成testdll.class。
再用javah testdll,则会在当前目录下生成testdll.h文件,这个文件需要被C/C++程序调用来生成所需的库文件。
2.C/C++
创建C/C++项目需要增加的头文件有jni.h、jni_md.h这两个文件是JNI中必须的;还有就是增加testdll.h。
对于已生成的.h头文件,C/C++所需要做的,就是把它的各个方法具体的实现。然后编译连接成库文件即可。再把库文件拷贝到JAVA程序的路径下面,就可以用JAVA调用C/C++所实现的功能了。
接上例子。我们先看一下testdll.h文件的内容:
#include #ifndef _Included_testdll #define _Included_testdll #ifdef __cplusplus extern "C" { #endif JNIEXPORT jint JNICALL Java_testdll_get (JNIEnv *, jclass); JNIEXPORT void JNICALL Java_testdll_set (JNIEnv *, jclass, jint); #ifdef __cplusplus } #endif #endif
在具体实现的时候,我们只关心两个函数原型 JNIEXPORT jint JNICALL Java_testdll_get (JNIEnv *, jclass);和 JNIEXPORT void JNICALL Java_testdll_set (JNIEnv *, jclass, jint);这里JNIEXPORT和JNICALL都是JNI的关键字,表示此函数是要被JNI调用的。而jint是以JNI为中介使JAVA的int类型与本地的int沟通的一种类型,我们可以视而不见,就当做int使用。函数的名称是JAVA_再加上java程序的package路径再加函数名组成的。参数中,我们也只需要关心在JAVA程序中存在的参数,至于JNIEnv*和jclass我们一般没有必要去碰它。
下面我们用testdll.cpp文件具体实现这两个函数:#include "testdll.h" int i = 0; JNIEXPORT jint JNICALL Java_testdll_get (JNIEnv *, jclass) { return i; } JNIEXPORT void JNICALL Java_testdll_set (JNIEnv *, jclass, jint j) { i = j+5; }
编译连接成库文件,这里就是testdll.dll。把testdll.dll拷贝到testdll.class的目录下,java testdll运行它,就可以观察到结果了。
三、总结
使用JNI可以在JAVA中调用其它语言编写的代码,在一定程度上消除JAVA的局限性和低效率。
参考文献:
【关键词】C语言 函数 类比教学法
【基金项目】防灾科技学院重点教研项目2012A04;防灾科技学院第一批精品建设课程。
【中图分类号】G42 【文献标识码】A 【文章编号】2095-3089(2013)06-0165-02
形象类比法属于讲授教学方法的一种,即借助于两类不同本质事物之间的相似性,通过比较,形象地将一种已经熟悉或掌握的特殊对象推移到另一种新的特殊对象上去的推理手段,也是教学中创设真实生动情景的有效工具之一。
C语言对于初学者而言,有一定的难度,学生在学习计算机方面存在比较大的弱点,思维逻辑能力不够强,空间视觉不够敏感。书中涉及到的一些抽象的理论知识,学生理解起来很难。为了帮助学生更好的理解抽象理论知识,在教学过程中,恰当的采用一些类比实例来帮助学生理解并提高学习的兴趣。
在C语言学习过程中,从前面简单的结构化思想转化到函数的模块化设计思想,因为知识的抽象性,学到函数这一章,很多同学反映学起来很困难,有一部分同学从这一章开始“知难而退”,放弃继续学习C语言。结合自己的多年实践教学经验,试从几个形象的例子类比来阐述如果理解复杂抽象的函数理论概念。
一、函数的概念
模块化编程是指将一个庞大的程序划分为若干个功能独立的模块,对各个模块进行独立开发,每一个模块用来实现一个特定的功能,然后再将这些模块统一合并为一个完整的程序。模块化编程使程序易于维护和提高程序段的利用率,这是C语言面向过程的编程方法,可以缩短开发周期,提高程序的可读性和可维护性。模块的功能,在C语言中,由函数完成。函数的工作原理:分而治之!一个C程序可由一个主函数main和若干个函数构成。
一个C程序的执行:从主函数开始,在main函数中调用其他函数,其他函数也可以互相调用。主函数一般都很简单,起到“驱动”的作用,把功能的实现都放在子函数里,一个子函数能做一件或者更多的事,可以说“主函数就是驱动程序,是用来驱动其它子程序(函数),更是整个完整程序的入口。”如果你要进入一个房子,你就必须先找到门,从门里才能进到屋子里去。C语言的主函数,就是你要运行的程序的“门”,不经过它,你就进不了房子。
music( )//音乐播放
{……}
movie( )//影视播放
{……}
online( )/*等等一序列子程序,这些子程序都需要main( )函数来驱动*/
{……}
void main( )
{
music( );
movie( );
online( );
}
程序模块化,使程序开发更容易管理,函数把较大的任务分解成较小的任务。比如:以前作坊式的制衣流程:先纺纱织布,然后剪裁制衣,之后制作扣子缝制完成制衣。这些工作由一个家庭作坊独立完成。类似于在C语言中由主函数完成所有的工作。现在的制衣流程:专业的织布公司、专业的制衣公司、生产加工扣子、拉链等辅料的公司。每一个公司类似于一个独立的“子函数”。
二、向函数传递值
如果函数的参数是基本类型变量和构造类型变量,则传递值的拷贝。
例如制衣公司现在需要1万条白色长30cm的铜拉链,他将把这些数值告诉加工辅料公司,加工辅料公司进行加工生产,即制衣公司“调用”加工辅料公司。这里的1万条、白色、30cm及铜质这四个信息属于传递的“参数”。这些参数对于制衣公司来说属于是“实参”,对于加工辅料公司来说属于“形参”。参数相当于公司之间的一份协议,它们的数据类型必须是一致的。制衣公司因为需求可以改变“实参”,例如改成加工2万条白色长30cm的铜拉链,这时“实参”改变的时候,“形参”也跟着改变;但是,加工辅料的公司没有自行改变制衣公司实参的权利,这就是函数的“形参”改变,“实参”不变的原则。
void Clothing_com( )//制衣公司
{
……
Accessories_com (1000,white,30,copper);//实参
……
}
void Accessories_com (int num,char color[10],float lenth,char quality[10])
//辅料公司,形参num:拉链数量;color:拉链颜色;lenth:拉链长度;quality:拉链质地
{ …… }
void main( )
{
Clothing_com( );
}
同一个函数可以被一个或多个函数调用任意多次,如加工辅料的公司可以和很多不同制衣公司合作。
三、向函数传递地址
如果参数是数组和指针变量,即地址,则传递地址值。
例如学校要铺草坪,即学校“调用”草坪公司。一种方法是让草坪公司在自己公司内种植草坪,草坪成熟后送到学校来,学校自己完成草坪铺种。一种方法是由草坪公司直接把草坪种植到校园里。
第一种方法,学校需要明确告诉草坪公司需要多大面积的草坪数,函数传递值的拷贝。
char *Lawn_Com(float area)//草坪公司
{
char col_lawn[100];
for(int i=0;i
col_lawn[i]='*';//用*代表种植的草坪
return col_lawn;
}
void college( )//学校
{
char *college_lawn;
college_lawn=Lawn_Com(30);//30是形参,草坪公司把成熟的草坪送到学校的college_lawn。
}
void main( )
{
college( );
}
第二种方法里,学校需要明确告诉草坪公司在学校的哪个位置种植草坪,草坪公司直接派遣工作人员去“实参”所指示的“地址”种植草坪就可以了,函数参数传递的是地址。当函数参数传递的是地址值时,通过地址找到实参,然后直接对实参进行操作。
void Lawn_Com(char col_lawn[30])//草坪公司
{
for(int i=0;i
col_lawn[i]='*';//用*代表种植的草坪
}
void college( )//学校
{
char college_lawn[30];
Lawn_Com(college_lawn);//草坪公司到学校的college_lawn
}
void main( )
{
college( );
}
四、函数的返回值
函数的返回值就是把函数执行完之后的结果带回给主调函数。函数可以有返回值,也可以没有返回值。
如学校“调用”草坪公司铺设草坪,在第一种方法中,学校要求草坪公司在其公司内部铺种草坪,把铺种成熟后草坪作为“返回值”送到学校,学校自己把草坪种到校园里,这是有返回值的函数。而在第二种方法中,学校要求草坪公司直接把草坪种到校园里,草坪种完就完成任务,草坪公司就不要再提交学校返回值了。
再如制衣公司“调用”辅料加工公司,辅料加工公司按照“实参”的要求把加工完的拉链成品作为“返回值”提交给制衣公司。
五、结束语
除了函数这一章外,笔者在C语言程学设计其他章节内容的教学中均尝试采用了形象的类比教学法,效果显著。类比教学法要求教师具有高度的概括能力,将知识进行归纳总结,在教学过程中,让学生将实际应用和生活所熟悉的事物与枯燥、抽象的概念理论进行类比,培养学生分析和解决问题的能力,提高学生的学习兴趣,让学生喜欢C语言,学好C语言。
参考文献:
[1]谭浩强.C程序多设计.第3版.清华大学出版社,2005
[2]韩莹,丰继林,单维锋.C语言实训教程.第1版.清华大学出版社,2013.1
关键词: 股票市场收益;原油价格;Copula函数;相关性
中图分类号:F830.91 文献标识码: A文章编号:1003-7217(2016)02-0032-06
一、引 言
原油是当今世界最主要的战略能源之一,对国民经济和金融市场的发展具有重大意义。历史表明国际原油价格的每一次大幅波动,都会给世界经济带来巨大影响。从油价波动引起股市波动的机理来分析,对原油进口国而言,油价上涨会提高国内的物价水平,降低居民的实际收入水平,从而抑制居民消费,不利于经济增长,股市也会受到影响。油价上涨还会导致中下游企业成本的增加,企业利润的减少会减弱生产积极性,不利于经济增长和股市的发展。同时,油价上涨必然导致生产企业减少石油的投入,降低企业的资本利用率,减少投资和资本存量,从而影响经济的增长,进而造成股市波动。油价的波动对发展中国家的影响比对发达国家的影响要大得多,主要是因为这些经济体依附于能源密集型产业,经历了快速经济增长,但能源使用效率低下[1]。鉴于新兴经济体的石油消耗不断增加,研究国际原油价格与股票市场收益的相关性具有显著意义。最近几年,“金砖五国”成为新兴市场的典型代表:金砖五国以快速的经济增长速度和巨大的市场潜力著称,逐渐成为世界经济增长的重要推动力量。因此,本文重点研究国际原油价格与金砖五国股市收益之间的相依结构。
金洪飞,金荦[2]用VAR模型和二元GARCH模型研究了中美股市价格和国际石油价格的收益率及波动的溢出效应,实证结果表明中国股市价格与国际油价之间不存在任何方向的收益率溢出效应和波动溢出效应,而国际油价对美国股市有负向先导作用,并且存在双向的波动溢出。Kunlapath S[3]等用Copula函数研究了股票收益和油价回报之间的相互关系,排除了石油天然气股票公司的股票指数以去除油价和石油天然气公司的直接关系。研究结果表明,在大多数情况下,油价和股票指数之间存在弱依赖性,这与先前的研究结果一致,然而石油消耗国和生产国的油价与股市具有强相关性。戚倩F,朱洪亮[4]应用VAR模型和误差修正模型,研究了中美股市价格和国际石油价格间的关系及油价对中国股市板块指数的影响,研究表明国际石油价格同中美股市指数都存在协整关系,在油价与美国股市指数的关系中,油价处于主导地位。Cuong C[5]使用非参Chiand Kplots和Copula函数分别刻画了油价对中国和越南的相关性,国际油价与越南股市之间具有左尾相依性,与中国的结果相反。Xiaoqian Wen[6]利用Copula函数探讨了在金融危机期间油价与股市之间是否具有传染效应。虽然目前存在较多对油价和股市之间的相关性研究,但是却严重缺乏对金砖五国这样的新兴经济体的研究。因此,本文结合GARCH和Copula方法研究国际油价和金砖五国股市收益的相关性影响。
二、Copula理论与方法
(一)边缘分布的估计
根据Copula理论,度量油价与股市收益之间的相关性,首先需要对油价和股市收益率分别建立一个边缘分布。用正态分布拟合金融时间序列的均值方程的残差,其结果不是很符合实际情况。GARCHGED模型能较好的描述金融时间序列的时变波动、高峰、偏斜、厚尾等分布特性。为了提高模型的拟合效果,采用基于广义误差分布(GED)的AR(p)GARCH(1,1)模型描述边缘分布。模型的均值方程和方差方程如下:
由表1可知,除了油价的均值为负数之外,金砖五国股市收益率均值均为正数,但数值都较小,均在零附近。俄罗斯的标准差比较小,其他几个市场的标准差较大。偏度显示正向冲击对于巴西和印度市场更为常见,而负向冲击对于其他市场更为常见。
得出油价和股市的收益率峰度都大于6,远远大于正态分布的3,峰度最高的是俄罗斯股票市场,其值达到了22.9。从统计结果可知收益率服从尖峰、厚尾分布。JB统计量明显拒绝收益正态性假设,LM检验表明变量存在ARCH效应。
表2给出了国际油价与金砖五国股市收益的相关系数结果。总体来看,油价和金砖五国股市的相关关系比较强。其中,Pearson线性相关、Spearman相关和Kendall相关的最大值分别是0.6870、0.5835和0.4585,除了油价与中国的相关系数较小之外,其他四国相关系数较大,说明油价与其他四国股市具有中等相关关系。这是因为巴西是石油开采大国,而石油更是作为俄罗斯的经济命脉存在,南非的矿产资源非常丰富,却唯独缺少石油这种战略资源。亚太地区近10年经济快速增长,可以抵消油价对股市的负向冲击。
为了提高模型的拟合效果,采用基于广义误差分布(GED)的AR(p)-GARCH(1,1)模型对油价和股市收益率进行建模,滞后阶数选取0至10阶,由AIC准则确定滞后阶数。表3给出了收益序列边缘分布的估计结果,GED分布的参数均小于2,说明尾部比正态分布的尾部更厚,反映收益率序列所得残差项的尖峰厚尾特征,也表明GED分布能够很好地描述收益率一般具有的非正态分布特征[8]。从结果可知,大部分估计系数和t统计量在1%的显著性水平下是显著的。表4是收益序列边缘分布模型检验结果。LB检验主要是检验序列是否为白噪声过程,由残差序列的自相关系数计算而得,检验结果接受原假设,在滞后1,5,10阶没有自相关;LM检验表明残差的平方项在滞后1,5,10阶没有自相关;KS统计量是根据估计得到的边缘分布,对原序列做概率积分变换后再运用KS检验方法得到的,其目的是检验变换后的序列是否服从(0,1)均匀分布。KS检验结果表明每个边缘分布服从(0,1)的均匀分布。
当边缘分布确定后,利用静态正态、Clayton、Gumbel、t Copula以及SJC Copula和时变SJC Copula函数描述油价和金砖五国股市收益的相关结构。Copula参数估计结果如表5所示。从正态Copula的估计系数来看,所有相关关系为正,油价与中国的相关程度最低,只有0.1042,油价与巴西的相关程度最高,显然与表2描述的相关程度相似。考虑尾部的不对称性,Clayton Copula的下尾相关系比较小,其中中国最小只有0.1274,但是对于Gumbel Copula的上尾相关系数而言,最大值有1.2477。SJC Copula的下尾和上尾系数都较小,但是下尾相关系数总体上大于上尾相关系数。因此当下尾相关时,市场管理者更应注重风险的回避。根据表5可知,时变SJC Copula的AIC最小,用来刻画油价与金砖五国股票市场相依结构最为合适。
表6给出了国际油价WTI与金砖五国股市的尾部相关系数。正态Copula函数用于描述线性关系,没有尾部相关性,尾部相关系数为0。从Clayton Copula和Gumbel Copula的尾部相关系数看出,油价与中国的尾部相关系数是最小的,而油价与巴西的尾部相关系数最大的。对于t Copula而言,因为它描述的是对称分布,故下尾和上尾系数值是一样的,油价与中国的尾部系数最小,这与表2的相关系数结果是一致的。从SJC Copula得出的结果可以看出,五个国家的下尾系数均大于上尾系数,说明油价的下跌对股市的影响大于油价的上涨对股市的影响。
参数估计结果显示油价与巴西的相关程度最高,因此对它们之间的相依结构进行分析。
图1、2分别给出了基于SJC Copula的油价与巴西股市的非对称结构。2009年以前,时变SJC Copula的下尾系数和上尾系数分别维持在0.2054、0.1289附近,相关关系相对较弱;此后的几年时间里,尾部相关程度明显提高,时变SJC Copula的尾部相关系数总体上比静态的尾部系数要大得多。同时还可以看出,油价与巴西股市收益的下尾系数要大于上尾系数,说明下尾的相关性比上尾的相关性要高。
石油价格收益率与金砖五国股市的相关程度取决于这些国家是否为石油进出口国家。2006年以前巴西一直是石油净进口国,此后开始抓紧陆地石油勘探和兴建炼油设施,石油产量不断增加,成为石油出口国。石油出口带来的收益增加会给石油出口的收入带来正向的影响。因此,股票市场的收益会受到来自国际原油价格的变动影响。俄罗斯是全球第二大石油出口国,财政收入大部分依赖于石油的收益。石油与股市之间的相关关系也比较明显。从负的偏度可知,油价与俄罗斯股市之间存在负向的关系,油价的下跌比上涨更能引起股市的波动。俄罗斯在911事件之后的石油产量不断上升,其他产油国却显著的减少产量。因此可以说石油是俄罗斯的经济命脉,俄罗斯经济收入与石油息息相关。印度和中国以及南非一直都是石油净进口国。从实证结果来看,石油与中国的相关程度最弱,印度次之。印度和中国都是非常大的经济体,从某种程度而言,印度和中国的股市取决于多种宏观因素的影响, 而不会单一的受到油价波动的冲击。伴随着中国金融经济体制的不断完善,中国证券市场更加规范和成熟,吸收和消化外来冲击的能力得到进一步增强[9]。这意味着中国经济具有强大的支撑和庞大的外汇储备,在糟糕的环境下保护市场。随着中国对外国投资者越来越开放,未来放开市场控制和汇率控制,这种弱相关程度可能会改变。
四、结 论
国际原油价格和股市之间的相关关系得到广泛的关注。但是通常金融变量的分布是非正态的,线性相关显然不太合适。本文采用Copula方法对油价与金砖五国股市收益之间的相关性进行描述。研究结果表明国际原油价格与中国股市收益呈现微弱的相关关系,而与其他四国股市收益的相关关系较为明显。对于Copula参数估计而言,由最优AIC可知,使用时变SJC Copula描述模型更为合适。在金融全球化的趋势下,不同国家或地区之间的金融市场的价格风险相依性逐渐加强。研究油价与金砖五国股市之间的相依关系对国际资产定价,风险管理和全球经济体的交互作用具有深刻的意义。首先,油价波动造成的非对称相依关系帮助投资者和政策制定者应对油价的变化,有助于谨慎投资,规避全球市场的风险传染。其次,投资者和决策者在国际金融市场上实现投资组合和资产配置多样化,维护发展中国家的利益。最后,动态尾部相关性的研究结果对风险管理也具有一定的指导作用,帮助政策制定者认清方向,当下尾相关性高于上尾相关性时,更应该及时规避油价波动带来的风险冲击,增强成员国进一步加强合作的意愿。
参考文献:
[1] Bhar R, Nikolova B. Oil prices and equity returns in the BRIC countries[J]. World Economy, 2009, 32(7): 1036-1054.
[2]金洪飞, 金荦. 石油价格与股票市场的溢出效应――基于中美数据的比较分析[J]. 金融研究, 2008,(2):83-97.
[3]Kunlapath S, Tatevik Z, David L,Wu X. Interdependence of oil prices and stock market indices:a copula approach[J]. Energy Economics, 2014, 44(4):331-339.
[4]戚倩F, 朱洪亮. 国际石油价格与中美股票市场影响关系的计量分析[J]. 金融理论与实践, 2011,(7):82-87.
[5]Nguyen C C, Bhatti M I. Copula model dependency between oil prices and stock markets:evidence from China and vietnam[J]. Journal of International Financial Markets Institutions & Money, 2012, 22(4): 758-773.
[6]Wen X, Wei Y, Huang D. Measuring contagion between energy market and stock market during financial crisis: A copula approach[J]. Energy Economics, 2012, 34(5): 1435-1446.
[7]Andrew J, Patton. Modelling asymmetric exchange rate dependence[J]. Social Science Electronic Publishing, 2006, 47(2):527-556.
关键词:冠脉内支架植入术;再狭窄; C反应蛋白;纤溶酶原激活物抑制剂-1
中图分类号:R815 R256.2 文献标识码:B 文章编号:1672-1349(2011)08-0925-02
预防冠脉支架内再狭窄是PCI必须面对的问题。再狭窄的基本病变包括炎症反应、平滑肌增生及细胞外基质的积聚[1]。研究表明糖尿病是再狭窄的危险因素[2],并且糖尿病患者的纤溶活性受损,机体的炎性反应激活,而纤溶与炎症机制是渗透再狭窄病理过程中的两个主要机制[3],其中血C反应蛋白(CRP)、纤溶酶原激活物抑制剂-1(PAI-1)是反映纤溶机制与炎症机制的常用指标,并已成为支架术后再狭窄强有力的预测指标[4],噻唑烷二酮类(TZDs)吡格列酮是否可以通过抑制血CRP与PAI-1而抑制支架内再狭窄?本研究旨通过观察吡格列酮对这两个因子的作用进而在理论上推测对支架内再狭窄方面的意义。
1 资料与方法
1.1 病例选择 连续入选山西医科大学第一医院2007年5月―2008年1月心内科行PCI术的2型糖尿病(T2DM)并使用胰岛素治疗的急性冠脉综合征患者20例。排除标准:既往有PCI史、接受过冠脉搭桥手术、心功能不全、肝肾功能异常、恶性肿瘤、感染、心肌炎、动脉夹层、血液病、伴有其他内分泌疾病的患者。
1.2 方法
1.2.1 给药方法 将入选20例患者随机分为观察组与对照组,各10例。观察组在PCI后24 h内加用盐酸吡格列酮(艾可拓)15 mg/d,维持3个月,两组均给予常规治疗。
1.2.2 观察指标 PCI术后24 h内、1个月及3个月测定血清高敏C反应蛋白(hs-CRP),血浆PAI-1含量。PAI-1测定:取清晨空腹肘静脉血1.8 mL注入0.25%枸橼酸钠抗凝液0.2 mL试管中,离心。hs-CRP测定:取清晨空腹肘静脉血2 mL,静置,离心,收集上清液。二者均于-80 ℃保存直至检测,由太阳生物技术有限公司提供的ELISA试剂盒测定。糖化血红蛋白(HbA1c)与血脂采用全自动生化分析仪测定。
1.3 统计学处理 计量资料以均数±标准差(x±s)表示,采用t检验,样本构成比的比较采用χ2检验。多次测量数据的分析采用重复测量数据的两因素多水平的方差分析。采用SPSS 13.0统计软件进行处理。
2 结 果
2.1 两组一般临床资料比较(见表1) 两组一般资料比较差异无统计学意义(P>0.05)。
表1 两组临床资料比较
2.2 两组hs-CRP、PAI-1及HbA1c变化(见表2~表5) 血清hs-CRP、HbA1c及血浆PAI-1浓度在不同时间点差别有统计学意义。详见表2。血清hs-CRP浓度处理因素和时间之间无交互作用,而血清HbA1c及血浆PAI-1浓度处理因素和时间之间有交互作用;但处理因素仅对HbA1c有统计学意义。详见表3~表5。即观察组与对照组支架后三个指标均有随时间逐渐降低的趋势,且血清HbA1c及血浆PAI-1浓度观察组较对照组降低趋势更明显,但使用艾可拓仅会使血清HbA1c降低有干预作用。
2.3 不良反应 在3个月的观察期内所有患者均未出现心绞痛、再发心肌梗死、急性或亚急性血栓形成、心源性死亡的不良心血管事件;也均未出现明显低血糖及体重的增加、未有肝功能异常(谷丙转氨酶水平≥正常上限的3倍)、肾功能及心功能的异常。吡格列酮组有3例出现轻微下肢水肿,未经治疗均于1个月内消失。
3 讨 论
冠心病患者血液中CRP及PAI-1水平是增高的[5]。而这二者可促进冠脉支架术后再狭窄[3]。CRP可上调细胞间黏附分子-1、血管内皮细胞黏附分子-1、E-选择素,介导巨噬细胞吞噬未修饰的LDL。CRP可诱导内皮细胞产生单核细胞趋化蛋白-1,增加单核细胞组织因子产生,而此因子是外源性凝血途径的重要启动因子,诱发血栓形成。CRP水平较高者炎症局部释放的某些血管收缩因子较多或血栓形成过程中血小板释放的血栓素A2较多,诱发血栓形成;PAI-1可在局部减少纤溶酶原的激活,促进病变血管内纤维蛋白和细胞外基质的堆积。
盐酸吡格列酮属于新型的TZDs,TZDs是PPARγ的人工合成配体,是一类新型的胰岛素增敏剂,TZDs可以改善高胰岛素和高血糖血症,使胰岛素抵抗缓解[6],改善脂质代谢紊乱。对血管的作用包括改善血管内皮功能,降低血压,减少动脉粥样硬化炎症替代标志[4],也可通过抑制前炎症细胞因子,黏附分子和细胞外基质蛋白的诱导生成,达到抗炎作用。C反应蛋白是公认的最常用的急性期蛋白。PAI-1除反应纤溶活性外也作为一种急性反应性蛋白,炎症的消除对纤溶活性的改善也起重要作用[7]。理论上TZDs有降低血CRP、PAI-1水平,但从本研究观察到合并T2DM并行PCI术的患者在术后3个月内应用盐酸吡格列酮除会使HbA1c的下降更显著,对于hs-CRP、PAI-1、血压及血脂则没有明显干预,可能的原因是:患者在观察期内坚持服用氯吡格雷及阿司匹林,皮下注射胰岛素,服用他汀类药物、血管紧张素转换酶抑制剂或血管紧张素Ⅱ受体拮抗剂,严格控制血压、血糖,并尽量使血脂达标,而血压、血糖、血脂达标及上述药物本身均有利于降低患者血中的hs-CRP、PAI-1[8-10]。在这些因素的影响下加用盐酸吡格列酮对于血糖的调节似乎作用较直接和有效,但对血压、血脂、血hs-CRP及PAI-1的直接影响则较小;TZDs启动的是一个基因调控的过程,3个月的观察时间较短;再狭窄部位药物浓度不足;PCI术后血hs-CRP、PAI-1还有一个自行回落过程对实验结果有影响。
参考文献:
[1] 潘长江.血管支架内再狭窄的机理研究进展[J].中国介入影像与治疗学,2005,2(4):314-317.
[2] 王旭开,何作云.胰岛素及IGF系统在冠状动脉再狭窄形成中的作用[J].心血管病学进展,2001,22(3):140-142.
[3] 刘海波,高润霖.血清C反应蛋白水平对冠心病介入治疗术中及术后并发症发生的预测价值[J].中国循环杂志,2000,15:264-265.
[4] 杨彬.氯沙坦在损伤血管重构中的作用及其机制的探讨[J].心脏杂志,2004,16(1):23-24;28.
[5] 朱西娥.糖尿病与冠心病(上) [J].中国乡村医药杂志,2002,9(11):57.
[6] 刘尊敬.PPARγ配体和相关血管病变的防治[J].国外医学:神经病学神经外科学分册,2004,31(2):117-120.
[7] 周明术.2型糖尿病患者急性时相反应蛋白检测的临床意义[J].陕西医学杂志,2005,34(11):1347-1349.
[8] 郭书红.氯沙坦对原发性高血压患者PAI-1、vWF、D-D的影响[J].中国厂矿医学,2006,19(3):199-202.
[9] 俞匀,朱大龙.PAI-1与代谢综合征[J].国际内分泌与代谢杂志,2006,26:49-51.
[10] 祁素霞.PAI-1、CRP与胰岛素抵抗及2型糖尿病的关系[J].医学综述,2007,13(3):212-214.
作者简介:赵宇卉(1976―),女,主治医师,医学硕士,现工作于山西省忻州市人民医院(邮编:034000);陈还珍,工作于山西医科大学第一医院。
关键词:面向对象;代码转换;C/C++
中图分类号:TP311文献标识码:A文章编号:1009-3044(2008)35-2181-03
An Automated Solution to Develop Object-Oriented C Program
RAO Jun-wen, ZHU Hong-ming
(Software School, Tongji University, Shanghai 201804, China)
Abstract: There are already solutions to make C language support Object-Oriented feature, but in those solutions the code framework supporting that feature needs to be provided by developers. In this solution codes will be written in C++-like grammar, while inside codes will be converted into Object-Oriented C language code, so no gap between Object-Oriented feature and C language exists. This paper analyzed the mechanisms of supporting Object-Oriented feature by using C language and codes converting, and then compared performance of this solution to that of using C++, so its advantage would be proved.
Key words: Object Oriented; codes converting; C/C++
1 方案概述
1.1 当前情况
嵌入式系统是当前最热门最有发展前景的IT应用领域之一,然而不得不承认的是,由于嵌入式领域硬件资源的限制,绝大多数的嵌入式软件还是用C语言或汇编来实现的,这一现状极大影响了开发人员的工作效率和质量。众所周之,C语言是一种不直接支持面向对象特性的语言,相对于C++等语言来说,其代码编写效率低,组织层次纷乱,封装性差,不利于代码重用。这样的代码,可读性差,维护难度也很大。如果为避免这种情况而采用C++等支持面向对象特性的编程语言又会顾此失彼。C++虽然支持面向对象特性,但它所具有的其他特性,如虚函数、多重继承、模板、异常、RTTI等,增加了代码的复杂性,使其占用更多硬件资源,降低代码运行的效率,这些都会极大的影响嵌入式系统的性能和成本。因此,在实际应用中使用C++开发嵌入式软件的情况也较少。
下面本文将介绍一种不依赖编译器的编程方案,它既具有C语言的执行效率,又支持面向对象特性。
1.2 特点
享受基本的面向对象特性,同时享受C语言的效率。
1) 本方案支持“类”的概念,包括私有成员变量和成员函数,并支持成员函数继承和多态。
2) 类的定义是通过特殊的hpp头文件来实现的,这个头文件的编写格式和C++基本相同。
3) 方案的重要部分是一个自动代码转换工具,它负责将hpp头文件转换成纯C代码。最终参加编译的代码都是纯C代码,因此,这个方案具有C语言所具有的代码容量小和执行效率高等特点。
4) 方案内部使用C代码框架实现类封装,继承和多态。
1.3 开发主要流程
(注:本文使用“demoClass”代表用户定义的某一个“类”。“parentClass”代表这个类的父类。)
1) 编写头文件demoClass.hpp和源文件demoClass.c;
2) 转换hpp头文件代码,生成中间C框架文件;
3) 编译C文件,生成二进制文件。
2 方案设计
2.1框架
demoClass.hpp:头文件,用于存放类的定义信息。
demoClass.c:源文件,用于存放类成员函数的实现。
demoClass.h:公共头文件,向外提供函数接口和数据定义。
demoClass_priv.h:私有头文件,仅供类内部的源文件使用,存放私有数据成员的定义及私有成员函数的声明。
demoClass_info.c:源文件,用于存放类的信息结构体,以及类的构造函数定义。
testMain.c:测试文件,使用类的对象实例完成特定功能。
2.2源代码编写结构设计
2.2.1头文件 .hpp VS C++头文件.h
1) 所有public函数须都是虚函数,除了构造和析构函数。
2) 只支持private数据成员。
3) 与本类虚函数对应的实体函数在private下声明。
4) 用以重载父类函数的实体函数在private下声明。
2.2.2源文件 .c VS .cpp
1) 添加#include "demoClass_priv.h"私有成员内容。
2) 对象初始化函数和析构函数:
demoClassInit():对象初始化函数,各函数指针初始化。
demoClassDelete():析构函数,完成“析构”动作。
3) this: 成员函数指针;thisd: 数据成员指针
2.2.3 代码范例
2.3 中间c代码设计及其机制
代码转换工具将通过给予的hpp文件,自动生成C语言代码框架,由他们实现各项面向对象的特性。
2.3.1 类结构
经过转换后的C代码分别使用两个结构体存储类的数据如图2、图3。
1) 使用demoClass 结构体存储函数指针集以及私有数据成员结构体对象的地址。
Typedef struct {
void * pData;
errCode ( *Delete )(CMPHANDLE);
errCode ( *virtualFunc_parent1 )(CMPHANDLE);
errCode ( *virtualFunc_demo1 )(CMPHANDLE);} demoClass;
在成员函数内部,“this”指针指向demoClass对象。而thisd 的内容就是 this->pData。
2) 使用demoClass_data结构体存储私有数据成员,由于其定义只在demoClass.c中,它并不暴露给外部类。
Typedef struct {
int privParentData1;
int privDemoData1;} demoClass_data;
虽然在对象demoClass中保存了对象demoClass_data的地址,但由于后者的定义并未公开,外部并不知道这个地址空间存储了哪些数据,而成员函数是在demoClass.c中定义的,他们是“看”的见这张定义表的,所以只有本类的成员函数知道如何“按图索骥”,这从一定程度上实现了隐藏类的私有成员。
3) 使用结构体ClassInfo的对象来存储每一个类的信息,包括类名,父类ClassInfo对象指针,demoClass和demoClass_data结构体大小。每个类对应的ClassInfo对象是这个类唯一的全局变量,任何时候用户可以调用类对应的“构造函数”制造出一个对象实例。
4) “this”和thisd指针
为了能使类的成员函数访问本类的其他成员函数以及本类的私有数据,成员函数必须知道本对象的地址和数据成员地址,在C++中,这些是由C++编译器内部提供this指针来实现的;在本方案中,每个成员函数都以第一个参数作为一个固定的输入参数,来获得本对象的地址,进而获得数据成员的地址。this是demoClass型指针,thisd是demoClass_data型指针,它们指向各自的结构体对象。
5) 类的创建和消亡
① “构造函数”demoClassNew()
demoClassNew()是这个对象唯一暴露在外的全局函数。用户可以通过调用它来创建对象。
demoClass* demoClassNew()
{demoClass* h= (demoClass*)ObjCreateAlloc(&demoClassInfo);
demoClassInit(h);
return h;}
a. 所有的类都通过调用ObjCreateAlloc (ClassInfo *)来实际创建对象,它依据给定的ClassInfo数据,获得demoClass和demoClass?_data的结构体大小,分别给它们分配内存空间,并返回demoClass地址,而demoClass_data的地址则保存在demoClass之中。
ObjCreateAlloc()函数将在后文中介绍。
b. 类被创建之后,由demoClassInit()来进行初始化,基本的动作包括函数指针和成员变量的初始化,还可以有用户自定义的动作。
② “析构函数”负责清理用完的数据或内存,并最终释放对象自己的内存空间。
2.3.2 继承
1) 派生类的数据继承:成员函数指针和成员变量
派生类通过照搬基类数据的方式来实现函数和数据继承。这种照搬的工作是由代码转换工具依据继承关系完成的。在生成的C代码中,用于存储派生类数据的结构体demoClass,其前端数据和基类结构体parentClass的数据完全一 致 ,新 增 加 的 函数指针紧接其后。demoClass_data新增加的成员变量也同理。这样,派生类就完全包含了一份与基类一致的公有函数指针和数据拷贝。当然,这些函数指针可能指向与基类不同的函数实体,其数据成员也可能存储不同的内容,这取决于构造函数的实现。
2) 构造和析构函数的继承
派生类的构造函数在自己的初始化函数开头,先调用基类的初始化函数,它负责初始化继承自基类的成员,在这个阶段,派生类被装扮成基类的样子。然后派生类执行自己的初始化动作,在这个阶段,派生类给新增加的函数成员和数据成员赋值,也可以修改来自基类的成员。
派生类的析构函数也分成两部分,先清理自己新增加的成员,然后在末尾调用基类的析构函数,来清理来自基类的成员,最终释放自己占用的内存。
3) 成员函数的继承
与上节类似,被重载的成员函数,其新的函数实体可以包含对基类成员函数的调用,也可以不调用,完全重写。
2.3.3 封装
1) 通过以上的结构设计,C语言中间代码实现了封装性:
任何一个对象创建之后,只能通过这个对象的句柄访问其公开的函数接口,外界看不见内部的数据,也无法通过合法的手段直接操作它们。而在对象创建之前,与这个类相关的全局元素只有两个:全局变量demoClassInfo和全局函数demoClassNew( )。
2) 公共根类
在这套方案中,任何一个类的对象,其创建和消亡都会涉及到这个类基础数据的处理,包括内存的分配和内部数据结构的初始化,这些是中间代码的内容,用户应无需关心它们,因此我们建立一个公共的虚基类rootObj,用它来封装这些内部的操作。用户如果要建立新的基类customClass,只需继承这个虚基类,填写好它对应的初始化函数customInit( )和析构函数customDelete()。根据代码的继承机制,新的类会递归调用对应的构造、析构函数,最终调用到虚基类rootObj的构造、析构函数,从而最终完成类的创建和消亡。
① 前面已经提到,类的构造函数demoClassNew()分成ObjCreateAlloc()和demoClassInit()两个部分。
ObjCreateAlloc()函数把所有的类都当作虚基类来创建,包括给两个结构体分配内存,并初始化pData指针。
CMPHANDLE ObjCreateAlloc(const ClassInfo* ci)
{rootObj* this;
rootObj_data* thisd;
this=malloc(ci->isize); //给demoClass分配内存
//给demoClass_data分配内存并把地址保存在pData中
this->pData = malloc(ci->dsize) ;
return this;}
② 虚基类的析构函数,负责释放类结构所占用的内存
errCode rootObjDelete(CMPHANDLE h)
{ THIS_PTR_DEF;
free(h);
return SUCCESS;}
2.3.4 多态
本方案把所有成员函数都设置成虚函数,在内部通过函数指针的方式来实现。当派生对象要重载基类对象的某个成员函数的时候,就把对应的函数指针指向新的函数实现实体,这样,一个同名的成员函数,根据类的不同完成着不同的操作,从而实现了多态。
2.4 代码转换工具的工作
总结如下:根据给予的demoClass.hpp文件,
1) 生成demoClass.h文件:
① include 父类的头文件parentClass.h。
② 生成demoClass结构体,其中,把所有的成员函数,转换成同名的函数指针,如果有父类,则把父类的成员函数指针放在开头。
③ 声明demoClassInfo变量和demoClassNew()函数。
2) 生成demoClass_priv.h文件:
① include 父类的头文件parentClass.h。
② 生成demoClass_data结构体,其成员就是类的所有私有成员,如果有父类,则把父类的成员变量放在开头。
③ 声明父类的初始化和析构函数,及成员实体函数。
④ 声明本类的初始化函数和成员实体函数。
3) 生成demoClass_info.c文件
① include本类的两个头文件 demoClass.h和demoClass_priv.h。
② 定义demoClassInfo变量,并赋值。
③ 定义本类的构造函数demoClassNew()。
这个代码转换工具由perl语言编程实现,可以集成在makefile中成为代码预处理的一部分。
3 此方案和C++方案的对比
在linux环境下,功能完全相同的两个程序:
4 结束语
通过此方案的转换手段,可以在基本保持C语言性能的基础上,开发出支持面向对象的C程序,而且不增加开发人员的额外负担。它大大提高了程序的可复用性和可维护性,为开发结构更加复杂、代码更加清晰易读的嵌入式软件系统提供了可能。在实际应用中,采用此方案的软件代码明显比用原C语言实现的同样功能的代码更加受开发人员的欢迎。
参考文献:
[1] 章远阳,杨芙清,邵维中.C++语言的面向对象特性分析[J].计算机工程与应用,1992(9).
[2] 张泰乐,肖孙圣,倪宏.面向对象基本特性的c语言实现[J].微计算机应用,23(6).
关键词:C语言程序设计;计算思维;抽象;自动化
美国卡内基・梅隆大学的周以真教授在2006年系统地提出了计算思维的概念[1]:计算思维指的是运用计算机科学的基础概念进行问题求解、系统设计以及人类行为理解等一系列思维活动。其后,陈国良院士和李廉教授归纳出三种典型的科学思维,即以观察和归纳为特征的实证思维,以推理和演绎为特征的逻辑思维,以抽象和自动化为特征的计算思维[2-3]。计算思维是计算机类课程的主要思维方式。
有关计算思维在程序设计类课程中的研究,已经引起很多学者的兴趣[4-6]。这些研究虽然从案例设计和项目过程等角度做了有益探索,但却忽略了对计算思维本质的讨论。C语言程序设计课程中,我们采用李廉教授的观点,即计算思维的本质是抽象和自动化。抽象指的是使用符号系统对问题进行精确而严格的描述;自动化指的是对这些符号系统施加一定操作并按照某种结构自动地执行。
一、C语言程序中的计算思维本质之一:抽象
有些C语言程序设计课程教学的一开始就提倡使用案例教学。这虽然能够使得学生可以迅速进入实际编程环节并建立直观感性认识,但案例教学由于往往出现“程序就是编程工具”的工具论现象,导致出现“只知其然,而不知其所以然”的学习后果,不利于学生的后续发展。
对于C语言程序来说,抽象指的是使用符号系统对求解问题进行精确而严格的描述,抽象的过程就是对实际系统建模的过程。实际上,程序是用来描述现实生活中某个实际存在的或不存在的系统。程序就是对系统的抽象。系统之所以存在,是因为系统具有一些关键特征和核心功能。程序中对系统特征进行抽象的就是操作对象,对系统功能进行抽象的就是函数。系统功能往往有多个且存在着复杂的调用关系。例如,求一个函数定积分的功能必然涉及求函数在某一个点的取值功能,如果该函数比较复杂且含有正弦、余弦和正切等三角函数,还需要继续调用求这些三角函数值的功能,形成多级调用;有时函数执行过程中还需要调用本身,形成递归调用。
C语言程序中的操作对象分为变量和常量。常量是对系统中的取值不变的特征进行抽象,如圆的圆周率;而变量是对系统中取值可以改变的特征进行抽象,如圆的半径。不管是哪类特征,都会有一个取值范围以及所允许的操作。例如,对于课程成绩,其取值范围一般是从0~100,而允许对该特征进行的操作可以是加法和减法等算术操作以及大于和小于等比较运算;而对于课程名字这一特征,就不能进行加法和减法这样的算术操作。C语言程序中用来对特征的取值范围及允许的操作进行抽象的概念是数据类型。C语言程序中的抽象模块如表1所示。
现实生活中,经常需要描述多个相同数据类型的一个系统特征,如所有同学的高等数学课程的成绩,可以使用一维数组来进行描述;而描述多个不同数据类型的多个系统特征,如学生的姓名、学生的身高和学生的年龄等,可以使用结构体来进行描述;如果要描述多个相同数据类型的多个系统特征,如全班所有同学的高等数学和大学英语课程的成绩,则可以使用二维数组来进行描述。
表1 C语言程序中的抽象模块
C语言程序中的元素 现实生活中的元素
程序 系统
函数 系统功能
函数调用 功能调用
数据类型 常量 系统特征
变量
一维数组 多个相同类型的一个系统特征
多维数组 多个相同类型的多个系统特征
结构体 多个不同类型的多个系统特征
链表或结构体数组 多个不同类型的多个系统特征的集合
二、C语言程序中的计算思维本质之二:自动化
计算思维的另一个本质是自动化。自动化指的是对符号系统建模的各种元素施加一些操作,并按照某种顺序的或非顺序的结构自动地执行。对于C语言程序来说,自动化体现为函数内部的语句在EIP寄存器加法操作支持下顺序自动地执行以及函数之间的调用在内存堆栈区支持下自动地进行跳转。EIP是32位机的指令指针寄存器,用来存放下一条要执行的指令的地址。EIP寄存器中增加值的大小需要根据实际存储指令的大小来确定。
对于C语言程序来说,自动化过程中执行的对象是语句。不同类型的语句,执行的结果和效用是不一样的。例如,一个变量定义语句“int a”的执行结果是在内存中分配4个字节的空间,一个返回语句“return t”的执行结果是将程序的执行流程返回到主调函数中。这些语句的组合构成一个个函数,程序的执行就是在某个函数之中顺序自动地执行以及在多个函数之间来回自动地跳转。
既然程序的执行过程是在某个函数之中顺序自动地执行以及在多个函数之间来回自动地跳转,这种自动执行需要有相应的计算机软件和硬件基础。支持程序自动执行的软件基础是操作系统,支持程序自动执行的硬件基础是计算机硬件结构,即冯・诺依曼原理的程序存储思想。当用户点击执行按钮后,程序被提交给操作系统来执行,可以不需要人为干预。此后,程序在操作系统中以进程的方式出现。操作系统协调内存、中央处理器和外存等硬件资源执行该进程。
函数中的语句之所以能够一个接着一个顺序地执行,主要依赖于EIP寄存器的加法操作。当一条指令执行完成之后,EIP寄存器在原有内容的基础上再加上当前指令所占存储空间大小,其内容便是下一条指令的地址。如此进行下去,就可以一个一个顺序地执行函数中的语句。
程序控制之所以能够在函数之间进行跳转,主要依赖于操作系统管理的内存堆栈区。内存堆栈区是满足“后进先出”操作约束的存储区。当操作系统开始执行用户提交的C语言程序时,首先开始从main函数执行,main函数的相关局部变量被压入栈中;当执行到被调函数时,被调函数的相关局部变量再次被压入栈中,程序控制转移到被调函数,且操作只能对当前栈顶进行,而此时栈顶存储的就是被调函数的相关局部变量;而当被调函数执行结束时,被调函数的相关局部变量从栈中退出,程序控制转移到main函数继续执行,此时栈顶存储的是main函数的相关局部变量;当main函数执行结束时,main函数的局部变量从栈中退出,整个程序执行结束。下列程序执行时的堆栈变化过程示意如图1所示。
#include "stdio.h"
double s(double r)
{ return r*r; }
int main()
{ double r;
double area;
r=2.0;
area= s(r);
printf("area=%f",area);
return 0;
}
图1 函数调用过程的堆栈变化
自动化过程实际反映了C语言程序解决实际问题的算法流程。算法是解决某一问题的执行步骤。一般而言,使用C语言进行编程之前,需要进行相应的算法设计,即构思解决实际问题的思路和步骤。一旦这些步骤变成C语言程序语句并形成一个完整的程序,就可以提交给操作系统自动地执行这些步骤,这正是计算机解决问题的高效率的体现。
三、以计算思维为导向的C语言程序设计课程教学
1.教学内容
针对计算思维的抽象和自动化两大本质特征,C语言程序设计课程的教学内容需要在原有的基础上特别强调一些针对性的观点。例如,C语言中的各种数据类型和数据结构可以完成实际系统中各种不同元素的抽象,一个函数之中的顺序语句自动执行的基础是EIP寄存器的加法操作,多个函数之间的来回自动跳转的基础是内存堆栈区的支持等。具体强调的观点如表2所示。
表2 教学内容中需要强调的观点
C语言程序设计
课程的内容 强调的观点
C语言概述 程序是对系统的抽象
抽象过程就是C语言的建模过程
自动化过程反映C语言的算法流程
数据类型、表达式和语句 操作对象是对系统特征的抽象
语句是系统自动化执行的基本对象
控制结构 控制结构是问题求解步骤的抽象
函数中顺序语句自动执行的基础是EIP寄存器的加法操作
数组 一维数组是对多个相同类型的一个系统特征的抽象,多维数组是对多个相同类型的多个系统特征的抽象
函数 函数是对系统功能的抽象
函数调用是功能调用的抽象
函数之间的来回自动跳转的基础是内存堆栈区的支持
结构体 结构体是对多个不同类型的多个系统特征的抽象
指针 链表是多个不同类型的多个系统特征集合的抽象
2.教学方式
计算思维的本质是抽象和自动化。C语言程
序设计课程一般都是面向大一新生,理解抽象和自动化进而培养计算思维,对于还处在计算机学习起点的学生来说是比较困难的。
对于C语言程序来说,抽象过程实际就是运用C语言中各种符号对所描述系统的建模过程,培养抽象的计算思维方式就是培养使用C语言描述实际系统的思维过程。因此,可以通过启发式教学方式引导学生思考如何使用C语言中的符号来描述系统。可以提出这样的一系列问题:C语言中如何描述一个人的身高?如何综合描述一个人的姓名、年龄和籍贯等?如何描述一个班中所有学生的高等数学成绩?如何描述各路公共汽车站的网状信息?通过启发学生对这些问题的思考,让学生所学的C语言中的各种符号不再“虚幻”,让学生真正理解这些符号实际是一种建模元素,每种符号有着其特别的抽象描述能力。
对于C语言程序来说,理解自动化过程必须借助一些形象化的手段。例如,借助于Visual C++ 6.0平台的单步调试功能,可以形象地演示上述C语言程序的自动化过程,如表3所示。
表3 C语言程序执行过程中EIP和ESP寄存器内容的变化
断点 EIP寄存器内容 ESP寄存器内容 当前栈顶函数
r=2.0;语句 00401068 0013FF24 main函数
area=s(r);语句 00401076 0013FF24 main函数
return r*r;语句 00401020 0013FF18 s函数
printf("area=%f",area);语句 00401089 0013FF24 main函数
从表3可以看出,随着EIP寄存器内容的增加,main函数中的语句顺序自动执行,即从语句“r=2.0”到语句“area=s(r)”再到语句“printf("area=%f",area)”。ESP寄存器是另一个重要的寄存器,它始终存放栈顶的地址。随着main函数对s函数的调用开始,栈顶工作函数由main函数变化为s函数;当s函数调用结束后,栈顶工作函数又由s函数回到main函数。
3.考核内容
针对C语言程序设计课程的计算思维培养要求,考核方式上必须从以考查语言的语法知识为主转变为以考查学生的系统建模能力和算法设计能力为主。
系统建模能力的考查主要针对计算思维的抽象特征。例如,可以给出各种系统特征,考查学生使用数据类型进行描述的能力。
算法设计能力的考查主要针对计算思维的自动化特征。当然,C语言程序设计课程中涉及的都是一些如迭代、枚举和排序等简单算法。可将这些算法封装成各种函数来进行调用,以考查函数中顺序语句的执行以及函数间的伴随参数传递的跳转来理解自动化过程。因此,必须以简单算
法设计和函数调用为重点考核内容,突出对函数接口设计和算法流程设计的考核。
参考文献:
[1] Jeannette M. Wing. Computational Thinking[J]. Communications of the ACM, 2006, 49(3):33-35.
[2] 陈国良. 计算思维[J]. 中国计算机学会通讯,2012,8(1):31-34.
[3] 李廉. 计算思维――概念与挑战[J]. 中国大学教学,2012(1):7-12.
[4] 张耀文. 基于计算思维的程序设计课程案例教学法研究[J]. 重庆电子工程职业学院学报,2012,21(3):149-150.
[5] 吴绍兵. 计算思维和程序设计能力的培养[J]. 计算机教育,2011(16):11-14.
摘要:现在单片机的程序设计,C51已经得到广泛的推广和应用,算是单片机的主流设计程序,甚至可以说作为单片机开发人员必须要掌握的一门语言了。本文简要介绍了Franklin C51交叉编译器的特点,较详细地讨论了C51语言程序设计的基本技巧及其与汇编语言程序的混合编程、中断处理过程等实际问题。
关键词:C51;C语言;编程
在研制单片机应用系统时,汇编语言是一种常用的软件工具。它能直接操作硬件,指令的执行速度快。但其指令系统的固有格式受硬件结构的限制很大,且难于编写与调试,可移植性也差。随着单片机硬件性能的提高,其工作速度越来越快,因此在编写单片机应用系统程序时,更着重于程序本身的编写效率。而Franklin C51交叉编译器是专为80C51系列单片机设计的一种高效的C语言编译器,使用它可以缩短开发周期,降低开发成本,因此目前它已成为开发80C51系列单片机的流行工具。
一、C51的编程规范
(一)注释
1.开始的注释:
文件(模块)注释内容:
公司名称、版权、作者名称、修改时间、模块功能、背景介绍等,复杂的算法需要加上流程说明;
函数开头的注释内容:
函数名称、功能、说明 输入、返回、函数描述、流程处理、全局变量、调用样例等,复杂的函数需要加上变量用途说明 ;
2.程序中的注释内容:
修改时间和作者、方便理解的注释等。注释内容应简炼、清楚、明了,一目了然的语句不加注释。
(二)命名:
命名必须具有一定的实际意义。
1.常量的命名:全部用大写。
2.变量的命名:
3.结构体命名:
4.函数的命名:
函数名首字大写,若包含有两个单词的每个单词首字母大写。
函数原型说明包括:引用外来函数及内部函数,外部引用必须在右侧注明函数来源: 模块名及文件名, 内部函数,只要注释其定义文件名 ;
1.缩进:缩进以Tab为单位,一个Tab为四个空格大小。预处理语句、全局数据、函数原型、标题、附加说明、函数说明、标号等均顶格书写。语句块的“{”“}”配对对齐,并与其前一行对齐;
2.空格:数据和函数在其类型,修饰名称之间适当空格并据情况对齐。关键字原则上空一格,如:
if ( ... ) 等,运算符的空格规定如下:“->”、“[”、“]”、“++”、“--”、“~”、“!”、“+”、“-”(指正负号),“&”(取址或引用)、“*”(指使用指针时)等几个运算符两边不空格(其中单目运算符系指与操作数相连的一边),其它运算符(包括大多数二目运算符和三目运算符“?:”两边均空一格,“(”、“)”运算符在其内侧空一格,在作函数定义时还可据情况多空或不空格来对齐,但在函数实现时可以不用。
3.空行:程序文件结构各部分之间空两行,若不必要也可只空一行,各函数实现之间一般空两行
4.修改:版本封存以后的修改一定要将老语句用/* */ 封闭,不能自行删除或修改,并要在文件及函数的修改记录中加以记录。
二、C51语言程序设计的基本技巧
C语言是一种高级程序设计语言,它提供了十分完备的规范化流程控制结构。因此采用C51语言设计单片机应用系统程序时,首先要尽可能地采用结构化的程序设计方法,这样可使整个应用系统程序结构清晰,易于调试和维护。对于不同的功能模块,分别指定相应的入口参数和出口参数,而经常使用的一些程序最好编成函数,这样既不会引起整个程序管理的混乱,还可增强可读性,移植性也好。
在程序设计过程中,要充分利用C51语言的预处理命令。对于一些常用的常数,如TRUE,FALSE,PI以及各种特殊功能寄存器,或程序中一些重要的依据外界条件可变的常量,可采用宏定义"#define"或集中起来放在一个头文件中进行定义,再采用文件包含命令"#include"将其加入到程序中去。这样当需要修改某个参量时,只须修改相应的包含文件或宏定义,而不必对使用它们的每个程序文件都作修改,从而有利于文件的维护和更新。
三、C51语言与汇编语言程序的混合编程
C51编译器能对C语言源程序进行高效率的编译,生成高效简洁的代码,在绝大多数场合采用C语言编程即可完成预期的目的。但有时为了编程直观或某些特殊地址的处理,还须采用一定的汇编语言编程。它们必须有完整的约定,否则数据的交换就可能出错。下面就以力源公司的10位串行A/D转换器TLC1549 为例说明C语言程序与汇编语言程序的调用。
四、C51中断处理过程
C51编译器支持在C源程序中直接开发中断过程,因此减轻了使用汇编语言的繁琐工作,提高了开发效率。中断服务函数的完整语法如下:
void函数名(void)[模式]
[再入]interrupt n [using r]
其中n(0~31)代表中断号。C51编译器允许32个中断,具体使用哪个中断由80C51系列的芯片决定。r(0~3)代表第r组寄存器。在调用中断函数时,要求中断过程调用的函数所使用的寄存器组必须与其相同。"再入"用于说明中断处理函数有无"再入"能力。C51编译器及其对C语言的扩充允许编程者对中断所有方面的控制和寄存器组的使用。这种支持能使编程者创建高效的中断服务程序,用户只须在C语言下关心中断和必要的寄存器组切换操作。
四、结语
C51编译器不但可以缩短单片机控制系统的开发周期,而且易于调试和维护。此外,C51语言还有许多强大的功能,如提供丰富的库函数供用户直接调用,完整的编译控制指令为程序调试提供必要的符号信息等等。总之,C51语言是广大单片机开发人员的强有力的工具。
参考文献:
[1]周立功.单片机实验与实践教程(三)[M].北京:北京航天航空大学出版社.2006
[2]柴钰.单片机原理及应用[M].北京:西安电子科技大学出版社.2009