时间:2023-05-29 18:21:51
开篇:写作不仅是一种记录,更是一种创造,它让我们能够捕捉那些稍纵即逝的灵感,将它们永久地定格在纸上。下面是小编精心整理的12篇c语言函数,希望这些内容能成为您创作过程中的良师益友,陪伴您不断探索和进步。
引言
C语言是国际上广泛流行的很有发展前途的计算机高级语言。它既具有一般计算机高级语言的可读性、可移植性的特点,又具有低级语言能够对计算机硬件进行操作的特性,因此,它适合用于操作系统的描述语言,用C语言开发系统软件和应用软件。但在87ANSIC中并没有规定C语言的图形功能,许多C语言教材没有介绍C语言的图形功能,这给许多需要用C语言设计完美、漂亮的用户界面的初学者带来了困难[1-2]。本文旨在通过介绍Turbo C 2.0的主要图形函数及一个具体的实例简介这些函数的用法。
1 与图形绘制有关的系统硬件[2-3]
要使计算机能够绘制图形,必须有一定的硬件基础作为保障。图形绘制的硬件基础主要是显示器和显示卡。显示器的工作方式一般有文本方式和图形方式。要在屏幕上显示图形,必须将其设置成图形方式。衡量显示器的主要性能指标是点距和分辨率。目前显示器常用的点距有0.39mm、0.31mm和0.28mm三种。高档微机配置的彩色显示器目前流行的是VGA档次,它最低的分辨率为640×480,中档的是800×600,高档的是1024×768。显示器必须与显示卡配套使用才能发挥其图形功能。显示卡所能支持的不同分辨率的显卡类型称为显示模式。下表给出Turbo C中常用的几种显示卡的图形模式:
2 Turbo C 2.0中与绘图有关的常用图形函数
2.1 设置图形工作方式的函数:initgraph()。
Turbo C绘图,首先必须设置显示器为图形方式。该函数通过选定参数可确定显卡的类型及图形模式。
如:
int driver,mode;
driver=IBM8514;
mode=IBM8514HI;
initgraph(&driver,& mode,“c:\temp”);
将图形方式设置为IBM8514类型,IBM8514HI图形模式,1024×768的分辨率,搜索路径temp为C盘一级子目录。
2.2 颜色控制函数setbkcolor(int color)及setcolor(int color)。
其中setbkcolor( )设置背景颜色,setcolor( )设置划线颜色。
2.3 基本绘图函数
A. line(int x1,int y1,int x2,int y2)
功能:从点(x1,y1)到点(x2,y2)画一直线。
B. arc(int x,int y,int stange,int endangle,int r)
功能:以(x,y)为圆弧的中心,以stange为起始角度,以endangle为终止角度,以r为半径作一圆弧。
C. setfillstyle(int pattern,int color)
功能:用参数pattern所确定的填充模式,用参数color确定的颜色进行填充。
D. floodfill(int x,int y,int color)
功能:填充一个含有点(x,y)在内的有界封闭区域,这个有界封闭区域的边界由参数color确定,填充模式与填充颜色由函数setfillstyle设定。
2.4 字符输出函数
A. settextstyle(int font,int direction,int size)
功能:在图形方式下设置字符的字体,式样和放大因子。
B. outtextxy(int x,int y,char &str)
功能:在窗口(x,y)的位置输出字符或字符串。
C. getch( )
功能:从控制台取得一字符且不输出,用来使程序暂停,按任意键后使程序继续运行。
3. 绘制一个圆饼型统计图的程序如下
#include
main( )
{ int driver,mode;
driver=VGA;
mode=VGAHI;
initgraph(&driver,&mode,“ ”);
setbkcolor(0);
setcolor(15);
arc(320,240,0,360,180);
line(320,240,500,240);
line(320,240,443,112);
line(320,240,266,70);
line(320,240,200,374);
setfillstyle(4,2);
floodfill(340,230,15);
setfillstyle(5,9);
floodfill(340,180,15);
setfillstyle(7,4);
floodfill(300,240,15);
setfillstyle(8,3);
floodfill(340,280,15);
setcolor(14);
settextstyle(1,0,4);
outtextxy(410,180,“14%”);
settextstyle(1,0,4);
outtextxy(330,110,“16%”);
settextstyle(1,0,4);
outtextxy(200,200,“34%”);
settextstyle(1,0,4);
outtextxy(340,310,“36%”);}
上述程序在Turbo C 2.0中上机通过编译、连接、运行,可得到精美的圆饼型图。读者通过阅读并上机调试运行该程序可以对C语言的图形设置、绘制;颜色的控制、填充等函数的应用有一个感性的认识,对复杂枯燥的C函数提高学习兴趣。
结语
目前许多C语言教材很少介绍C语言的图形功能,而许多C语言学习者对C语言的图形功能很感兴趣,为帮助初学者学习C语言绘图函数并提高学习兴趣,本文简单介绍了C语言一些常用的绘图函数及其应用,权当抛砖引玉!还有一些图形函数没有列出,读者若有兴趣可参阅《C语言函数大全》。
参考文献:
[1]徐士良.PC机C图形编程手册.北京:清华大学出版社,1994.2.
[2]谭浩强.C程序设计(第二版)[M].北京:清华大学出版社,1999.
关键词:C语言;程序设计;函数;教学方法
中图分类号:G642 文献标识码:A 文章编号:1009-3044(2013)22-5108-04
C语言一般作为普通高校各理工专业的第一门程序设计语言[1],学好C语言对学生学习后续计算机课程至关重要。C语言的基本单位是函数,函数是C语言教学的一个重点。因为C语言中的函数跟现在所有流行的语言中函数的用法都不太一样,以函数为切入点,可以比较直观的辨别出来面向过程和面向对象的一个区别,有利于学生理解到底什么叫面向过程的语言,什么叫面向对象。所以C语言的函数十分重要。
1 教学方法
函数的教学与流程控制不一样,流程控制中if、while、for知识点是由浅入深,一步一步来的。而函数的特点是,一个程序里会涉及到函数的很多知识点,所以只要把一个程序搞清楚了,那其他程序也就全懂了。针对函数的这个特点,我们的授课思路是首先用通俗易懂的例子来引入问题,使学生理解为什么需要函数;教师实际演示编写程序,调试执行程序让学生理解C函数的执行过程;通过对程序有意设置语法错误和空白内容的方法,使学生了解如何定义函数、调用函数,帮助学生掌握函数语法知识;设计案例,由浅入深,将知识全面化,系统化;布置作业,帮助学生加深对知识点的理解,激发学生的创新思维。
1)用通俗易理解的例子来引入问题
讲授任何一个知识,首先讲为什么需要这个知识[2],只有这样学生才会自然接受,这一点很重要。引例的选取最好难易适中,能充分调动学生的积极性。
教师提醒学生,在这个程序中,有三段代码的操作是重复性的。那么如果这个程序有一万个地方要输出两个数的最大值,那就意味着这段代码要重复一万次。这样写肯定不合适。至此引入函数加深学生对函数的感性认识。引导学生思考为什么需要函数,原因是函数可以避免重复性操作。
通过调试执行,学生可清楚了解到函数调用与返回的实现过程。程序从主函数main进入,当遇到函数调用时,暂停执行主调函数,然后转去执行被调函数。首先为被调函数分配调用过程中所需的数据区,包括调用后的返回地址,函数的形参以及各种局部变量,然后把实参的值复制到形参中去,接着把控制权转移给被调函数,完成调用后,如果函数有返回值,先保存计算结果,然后释放被调函数的数据区,返回主调函数暂停的位置(调用前保存了返回地址)继续执行。
仍然采用调试执行本程序,加深学生对函数调用过程的理解。将函数调用过程讲深讲透非常重要,这是科学性的要求。理解了函数的调用过程,就会理解什么是递归,什么是变量的作用域与变量的生命期。
3) 设置错误寻求正确答案的教学方法和填空式的教学方法
传统的教学方法中,一般集中式的讲述语法知识,非常枯燥,学生学了也不会编程不会应用。在课堂教学中,可以有意设置语法错误,根据编译所提示的错误,引导学生思考并修正错误;或者是有意识地将一些内容空出,要求学生先读懂再填空,然后运行程序,调试程序,直到得到正确的运行结果。这样可激发学生的探索欲望,加深对语法的理解,也提高了学生的学习能力。
4)案例——任务驱动的教学方法
至此,学生已经掌握了函数的大部分知识点,但是在以往的教学中,通常面临一个问题,当学生自己写程序的时候,他们通常将语句一并写在main里,而不选择用函数实现。究其原因,还是学生对如何定义函数,以及如何在主调函数中调用自定义函数不够熟练,没有体会到函数的运用给编程带来的极大的便利。针对这个问题,我设计了两个案例要求学生完成。案例的选择要难度要由浅入深,循序渐进,每个案例欲教授的内容要目的明确,重点突出。
通过这个库函数调用的案例,学生学会了如何自定义函数,加深了对函数库、库函数、连接程序、头文件的相关概念的理解,明白了函数是为解决大量同类型的问题而设计的,可提高代码的可重用性,将来无论哪一个程序需要这个功能都可以使用它,就好比我们printf、scanf、pow一样,也学会了在具体的应用中该如何自定义函数,如何确定函数的返回值类型和函数的形参列表。
5)精讲多练的教学方法
C程序设计内容多,课时少,课堂上教师要做的不是拼命多讲,可以通过作业让学生去自学。也不是要拼命讲明白,因为程序只有学生自己想明白了才能为他所用。不能过于依赖教材,要引导学生将所学知识联系起来,现场演示设计程序的思维过程,讲清知识的深层原理。布置作业,作为课堂内容的补充和深化。学生通过查资料动手实验,根据完成作业的情况,教师可以发现问题所在,在上机实践课中重点讲解。
通过本案例,使学生理解并掌握函数的几个重要概念、实现方法和编程技巧。
函数教学案例五:通过调用swap函数,交换主函数中变量a,b的值。
这个作业的要点是swap函数中的形参在调用完毕空间就释放了,所以,虽然两个形参变量的值交换了,但是a,b的值却没变。
大部分学生接着就想,能否返回两个值带回主函数,编程实践发现无法做到,因为被调函数只能返回一个值。
那怎么办呢?这时候老师可以告诉学生,在后续课程指针章节可以找到答案。这样给学生留下思考余地,启发学生去思考,有利于提高学生的学习能力,培养学生的创新思维[2]。
2 结束语
C语言函数的教学很重要,使学生理解函数并且学会应用函数是教学的关键。在后续讲解数组、指针、结构、文件时,都会与函数的知识综合起来,例如,将数组名作为函数的参数,指针作为函数的参数,结构指针作为函数的参数,文件操作函数等,学生能更好地掌握函数的定义和调用的方法,也会慢慢理解为什么说C语言是由函数所组成的。该文所探讨的C语言函数的教学方法已经应用在实际教学中,激发了学生学习的自觉性和主动性,提高了教学质量,取得了良好的教学效果,希望对同行有所帮助。
参考文献:
[1] 高枚,杨志强,许兰兰,龚沛曾.C/C++教学改革的探索与实践[J].计算机时代,2005(11).
[2] 谭浩强.《C程序设计》发行1000万册的启示[J].北京联合大学学报:自然科学版,2011(4).
关键词: Sleep;循环;硬件思维;指针
中图分类号:TP312.1 文献标识码:A 文章编号:1671-7597(2012)0210144-01
0 引言
循环嵌套对于初学者来说是个难以理清的知识点,尤其是内层循环和外层循环之间的关系也只能是靠多加练习来体会;虽然断点测试可以清晰的看到运行情况,但是复杂的地址和中间值对于初学者来说更难理解。我们这里借用一些辅助函数,比如说Sleep函数,来使嵌套的层次更加清晰,使break和contimue的对循环的影响更加清楚。指针更是让许多学生望而怯步,归根到底是学生对于硬件知识的缺乏,我们这里采用先对学生讲解内存存储原理的方式,是学生对指针的认识更加直接和深入。
1 Sleep函数在循环嵌套中的妙用
在学习循环嵌套的时候,我们往往都是写完代码后一次性将最终结果显示在窗口,或者一次性将所有的结果显示在窗口,这样就很难看清每次循环所做的具体事情。虽然我们可以用断点测试来看程序运行的具体情况,但是断点测试对于初学者来说太过复杂。在这里我们用一个比较直观的例子,再加上一些辅助函数来了解循环和循环嵌套的详细过程。
例1:用C语言实现一个格式为“分:秒:毫秒”,范围为00:00:00~19:59:99。
我们这里首先根据题意分析可得,1秒=1000毫秒,这里我们毫秒采用两位,即99代表990毫秒。我们采用6个int类型变量m1(分的十位),m2(分的个位),s1(秒的十位),s2(秒的个位),ms1(毫秒的百位),ms2(毫秒的十位),他们之间的进位关系为:1m1=10m2,1m2=6s2,1s1=10s2,s2=10ms1,1ms1=10ms2,利用这些变量之间的进制关系,我们采用6层for循环嵌套来实现,循环部分的核心代码如下:
这样实现的结果根本做不到秒表读秒的效果,也看不出循环执行的具体层次。所以我们引入Sleep函数,并利用“\r”来打到比较好的读秒效果。在VC里面加上头文件#include,便可利用Sleep函数将程序挂起(暂停)一段时间,时间长短取决于Sleep(unsigned long)函数中的参数,其参数代表毫秒,Sleep(1)表示将程序在此挂起1毫秒,在本例题里,我们采用Sleep(10)表示将程序每执行一次printf函数就挂起10毫秒,刚好和秒表的右边第一位跳一次的时间相等。利用“\r”返回行首,这样我们改造后的代码为:
return 0;}如此一来,我们就实现了秒表的效果。通过秒表的贴近日程生活的进位显示现象,我们可以非常清晰的看出循环嵌套之间的层次,从而对循环嵌套有一个一步到位的清楚认识;并通过添加Sleep函数的使用,还对学生自主拓展知识有一定的引导作用。
2 硬件思维在理解指针中的妙用
语言课是学生的入门课,由于没有地址的概念,所以对于指针的认知一直都是难点。我们这里先向学生介绍内存及内存地址的组织情况,从内存地址的角度来讲解指针,这将是学生对指针的认识和掌握有个一步到位的认识。
所谓指针,其实就是所需的操作数的地址,我们这里以简单的直接一次间接寻址为例,我们先看一下内存和内存地址的简单组织情况:
我们举一个简单的例子来说明,例如有如下定义:
int a=1000,*p;
p=&a;
这里的内存和内存地址结构我们就以上面简单的形式组织,以典型的32位字长为例,变量值和指针(地址)均可放到内存单元中。刚开始定义变量a并赋予其初始值1000的时候,我们是将变量a的值1000存到000号单元中,然后定义指针变量p时是将008号单元分配给指针变量p,也就是说008单元中放的是指针变量p;p=&a操作是让指针变量p指向变量a,也就是将008单元中的指针变量值具体化为000,在以后的通过指针p引用变量a的时候,*p中的*的意思是指:取指针变量p的值(000)作为地址去找操作数,而000号单元中放的就是变量a。这也就是在引用时,*p和a是等价的。
利用内存结构还很容易在函数中用指针传参能改变变量的值,而通过普通变量传参因为作用域的问题而无法改变变量值。例如有如下代码:
输出结果中,a=1b=4,在调用函数fun的时候,第一个参数传的是变量a的值,但是main函数中的a和fun函数中的a并不是一个变量,000单元中的变量a是main函数中的a,003中的a是fun函数中的a,a=3是对fun中的a赋值,并未对main函数中的a做出任何改变;但fun函数中的*q=4是对q中的地址001中的变量b进行赋值,而001中的变量b刚好是main函数中的b,所以main函数中的printf语句输出的a还是1,而b则变成了3。
以上就是硬件思维在指针学习中的作用。
参考文献:
关键词:C语言;函数;调试技术
中图分类号:G642.4 文献标志码:A 文章编号:1674-9324(2014)11-0085-02
C语言是一门函数式语言。学习C语言编程必须学好函数的使用。笔者在多年的教学过程中,发现学生在学习函数的过程存在一些问题。虽然这些内容教师在课堂上都十分认真地讲解,但有些学生还是觉得内容很抽象,不容易理解。程序调试技术一般用在程序查错上。在程序调试的过程中,可以看到程序的执行过程,包括函数的调用过程、形参实参的传递,变量的内存地址等内容,这样可以很直观地给学生讲解函数的相关内容,因此笔者在函数的教学中使用了程序调试技术,使教学内容不再抽象,而是具体化,使学生能够更好地掌握相关知识,达到了较好的结果。
程序调试技术在函数教学中的具体使用:
1.通过调试技术直观地查看函数的调用过程。首先设计一个简单的使用函数的实例,jc函数实现计算n的阶乘。在main函数中通过函数调用来求任意一个整数的阶乘。double jc(int n),{ double mul=1;//……2,int i;for(i=1;i
2.通过程序调试技术了解函数参数传递过程和局部变量的概念。在函数教学中,形参和实参的关系往往是学生容易出错的地方。形参和实参是两个不同的变量,实参的作用就是给形参传值。而函数的形参以及函数内定义的变量都是函数的局部变量,只能在该函数中使用。而在调试中通过查看变量的值可以很清晰地看到这些知识的作用,则比较生动具体。在上例中,程序在断点停下后,选择debug工具栏中的watch项,打开watch对话框,在对话框中输入num和n,如图3所示,此时num的值是5,而由于jc函数还没有被调用,形参n还不存在。然后选择Step into(F11)项,跟踪进到jc函数内部查看,注意观察watch对话框的变化,发现n的值变为5,而num失效了,如图4所示。这说明程序的执行进入到jc函数,形参变量n被创建并从实参获得了值5。而num是main函数的局部变量,在其他函数中如jc函数中是无法访问的,从而失效。
3.通过调试技术加强对指针做函数参数的内容的理解。在讲解函数的过程中,指针做参数是重点和难点之一。教师在教学过程中强调指针做形参,可以突破局部变量的限制而访问到其他函数的局部变量,这在以后的函数使用中经常用到。但学生觉得很难理解。笔者通过调试技术运行一个实例,查看实际的运行过程,来加深学生对内容的理解。首先设计一个简单的指针做参数的实例。void fun(int * q){*q=10;//…….2}int main(){int n=89;int * p=&n;fun(p);//…….1printf("n=%d\n",n);return 0;},在标号1处设置断点。调试运行该程序,在断点处停下,p是fun函数的实参。此时选择debug工具栏中的watch项,打开watch对话框,分别输入p和&n,如图5所示,它们值相同,都是0x0012ff44,表示n的内存地址。然后选择Step into项跟踪进入fun函数内部执行,由于p和n是main函数的局部变量,在fun函数内部无法访问,它们的值失效。然后,在watch对话框中再输入q和*q,则可以看到如图6的内容。说明形参q从实参p获得了值0x0012ff44,即q也保存了main函数中n的地址,而*q的意思是通过q保存的地址访问该地址所表示的变量。继续单步执行,返回到main函数执行,此时查看n的值,果真变为了10。即在fun函数内部通过指针变量改变了main函数中局部变量的值。
笔者在实际的函数教学中采用了程序调试技术,让学生直观地看到了程序的运行过程,从而加深了学生对函数调用过程、参数传递、指针做参数等内容的理解。学生反应良好。计算机技术总是在不断的发展,教师还要不断地探索更好的教学方法,使C语言课程的教学质量进一步提高。
参考文献:
[1]谭浩强.C程序设计(第四版)[M].清华大学出版社,2010.7.
关键词:C语言;编程;学习策略
中图分类号:G642 文献标识码:A 文章编号:1009-3044(2016)22-0080-02
1 C语言产生的背景
计算机程序设计语言经历了从机器语言、汇编语言到高级语言的发展过程,机器语言是最原始的代码语言,可以直接识别,也是第一代的计算机语言,随着社会化发展变化,后来用汇编语言中的助记符代替操作码来编写程序,但由于汇编语言自身特点也存在局限性,根据社会发展需求于是产生了C语言,C程序是经过编译后可以直接执行的面向过程的高级语言。
C语言是在BCPL语言的基础上发展起来的。70年代初,美国贝尔实验室根据工作需要研发出BCPL语言,后来在1973年,贝尔实验室在BCPL语言的基础上研发出了C语言程序,后来经过多次改版本,到了80年代初,美国国家标准化协会根据C语言的发展变化,制定了新的C语言标准,一直沿用到现今,为大多数编程者所遵循。
2 C语言的特点及优势
C语言是国际上广泛流行的计算机高级语言,现如今被越来越多的计算机编程人士所使用,它不仅可以用来编写软件代码,还可以用接近自然语言方式描述问题,同时兼顾高低级语言的优点,主要体现如下方面:
1)C语言简便,结构严谨、操作灵活。
2)C语言的运算符较多且表达式类型丰富,编写程序节约时间,工作效率高。
3)模块化程序设计方法,可以把一个大问题按层次分解成多个小问题的设计思想,使编程更加灵活,算法设计自由度大。
4)C语言生成目标代码可操作性强,程序执行效率高。
5)C程序图形功能较强,程序可移植性好。
由于C语言这些特点及优势,使它成为计算机编程者必学的程序设计语言。
3 C语言编程中常见的现象
第一,大一新生刚入校门,心理比较放松,大学的学习生活还未适应,就要开设程序设计语言课程,对于他们来说不知从何学起,心里没底。上机实践课时,C语言编程语法较严格,出现错误就不能运行出结果,导致学生在学习过程中慢慢失去信心和成就感,学习兴趣和热情不高。
第二,C语言的算法和结构有点复杂,理论的东西很难记住,听起来感觉很枯燥无味,不容易理解。
第三,课时安排不够合理,致使教师在每节课讲授内容必须保证进度,这样就给学生无形中增加了压力。特别是在刚开始学习时,学生兴趣都非常高,对程序设计课比较好奇感兴趣,但在后来的学习过程中,面对每节课大量的枯燥代码和编程理论及语法规则的限制,慢慢跟得有些吃力,往往是前面的内容还没有消化完,后面又开始新的内容,时间长了就会让学生产生消极心理,产生厌烦情绪,另外学习方法不对,也会导致学生缺少学习兴趣。
4 C语言编程的学习策略
4.1 熟悉程序开发环境
C语言程序编写一般经过程序编辑、程序编译、程序连接到程序运行结果检测这几个步骤来实现,建议在Visual C++编程平台(也可选择其他平台)进行实验,好快速掌握C语言编程环境,熟悉程序代码的调试过程, 为接下来的学习编程操作打下良好的基础。
4.2 掌握C语言语法规则,养成良好的编程习惯
学习C语言基础就是要学习它的语法规则,学习某种语句或命令。首先要了解它的规则是什么,作用是什么,怎么实现等,这样可以为后面的学习打下坚固的堡垒作用。比如什么是常量、函数定义的格式及其意义是什么,使用什么样的语句去运用它,这样想明白了编起程序来才能得心用应手。那么在编程中除了要掌握好语法规则外,还应培养较好的编程习惯,这样可以提高工作效率,减少代码出错的机会。
4.3 精通算法技巧
学习编程就是要学习它的思维方法,画流程图就是在构建写程序思路的过程。当画好一个流程图时编程思想也就出来了,再结合掌握的语法规则,在计算机环境下调试就可以出来了。程序=数据结构+算法,算法就是解题思路与步骤,掌握分析问题、解决问题的方法,就是锻炼分析、分解,最终归纳整理出算法的能力。计算机语言是表达方式,算法和数据结构才是灵魂。算法可以用自然语言或流程图来表示,在使用流程图时,应掌握一些流程符号,即用一些图框来表示各种操作,直观形象,易于理解,从而达到根据算法流程图来完成程序的输写。
4.4 掌握四种结构
C语言学习中掌握四种结构即顺序结构、选择结构、循环结构和模块化程序结构非常关键,因为这种这四种结构决定了C语言代码的执行过程,相当于是算法的流程体现,它们彼此可以互相嵌套。C语言对数据的处理是通过“语句”的执行来实现的,一条语句完成一项操作(或功能),一个为实现特定目的的程序应包含若干条语句。
在实际编写代码过程中,常常将前三种结构相互嵌套调用,以此设计出相应的算法来解决工作中遇到的问题。如果是设计大型项目的话,编写出的程序往往需要完成的功能较多,数据结构较复杂,长篇符的代码并不利用管理和维护,为了解决这种状况,如果采用C模块化程序设计思路就方便较多。
C模块化程序设计采用自顶向下逐步求精的设计结构,将一个大问题按层次分解成多个小问题的设计思路。一般由主控函数和子函数组成,即指将一个很大的代码段划分为一系列功能独立的小代码段部分,每个代码段完成一个指定的功能,那么将这些代码段合在一起就是一个完整的功能模块。其中每个代码段实质就是一个具体的独立子函数,函数与函数间可以相互调用,但不能相互嵌套,通过主控函数可以调用子函数(子函数不能调用主控函数)可以将各个函数模块聚合为一个整体完成相应的功能。因而,定义函数、定义函数名(函数名表示功能)、函数调用和返回值等就很关键和重要,初学的人要通过不断地上机实践才能掌握编程的流程和精髓。
4.5 熟知函数定义
函数就是完成相对独立功能的程序段,它具有独立性,代码适中,分析问题层次清楚等特性。函数由函数说明和函数体两部分构成,函数说明包括函数值类型、函数名、参数类型及参数说明;函数说明之后的花括号“{}”部分为函数体,里面由C语句构成。函数调用时,实参与形参应保持个数、次序及类型的一致性,以确保实参与形参之间数据的正确传递,为提高编程效率打下良好的奠定基础。
4.6 具备数学知识
编程是人把要表达的思想,通过计算机语言表达出来 所以最重要的就是数学逻辑思维。在C语言学习过程中,较好的逻辑思维可以比较容易学习C语言编程分析,选择更简捷的运算流程,C的核心语法并不要求很高的数学知识,高中阶段接触到的概念性的知识就足以应付。因而,数学知识对学习C语言重要性还是比较大。
4.7 会调用C语言库函数
库函数就是把函数放到库里,是别人把一些常用到的函数编完放到一个文件里,供程序员使用,程序员用的时候把它所在的文件名用#include指令加到里面就可以了(尖括号内填写文件名),例如#include。在编程时候需要调用库函数.
4.8 指针在C语言中的灵活运用
指针是C语言的一种数据类型,是指向变量和对象的地址,是C语言学习的重点内容。 指针的用途非常广泛,假设想通过函数改变一个变量的值,就得用指针而不能用值传递,特别是对象的数据量非常大,往往编程人员就会用指针来做形参,只需要传递一个地址就可以,大大提高了工作效率。另外,指针变量可以访问内存地址,也可以访问数组和字符串,使编写的C程序代码更简洁,效率高。指针的学习在C语言中是关键的内容,也是学好C的精髓所在,为了高质量地完成程序的编写,就需要掌握指针在C语言中的灵活运用,那就要能通过上机反复地调试代码,从实践中总结问题,完成指针的学习。
4.9 读代码和程序
C语言编程不只是理论性的知识,它还要求上机动手操作能力更强一些。每次C语言课的学习,只有通过上机输入大量代码的练习,才能发现错误代码段,分析解决存在的问题,不断总结经验,巩固课堂上老师所讲的内容。C语言编程不是单纯靠理论记忆就能学好的,它需要大量的上机实验来巩固,才能加深知识的消化理解,开拓编程思维,提高解决问题的能力,培养良好的编程态度。
读程序和分析他人写的代码也是学习C语言较好的途径,仔细研读程序时,注意分析别人是如何运用编程技巧的,研究它的实现方法和程序设计技巧,提高自己的程序设计能力,直到每一行都理解了,然后找几个题目编写,自己试图写出程序,反复实践,这样就能从错误中分析代码出错的原因,进行调试正确的代码段,不断积累经验,反反复复直到搞懂为止。时间久了,慢慢就对程序的掌握有一个比较清晰的过程。
4.10 借助网络资源
C语言的学习在课堂上的知识还是有限的,如果想获取更多的知识,可以借助网络平台来完成资料的补充。一方面可以在教学网站上得到相关的学习内容;另一方面可以登录相关论坛或C语言专题微信群参与讨论,获取学习经验,探讨编程技巧,这样对于学习者来说都非常便利。
5 结束语
C语言是计算机编程语言中应用最流行的一种高级语言,在C语言学习过程中,本文针对C语言特点、出现的现象和学习策略进行了分析,只要学习者认真领会C语言功能的强大,具备持之以恒的学习韧劲,一定会在实际学习中取得优异的结果。同时,C语言作为高校公共基础课,学习好它不但能提高自己的编程能力,还对整个计算机语言的学习起到奠基作用,为社会培养综合型人才更好的服务。
参考文献:
关键词:DSP C语言 并行汇编 混合编程
TMS320C62X是美国德州仪器公司TI的新一代高性能定点数字信号处理器(DSP)芯片。基于DSP的软件设计问题,就是采用编程语言进行算法实现并使程序效率尽量满足实时性要求。TI DSP的软件设计可以采用汇编语言、高级语言C/C++以及C语言与汇编语言的混合编程。完全采用汇编语言编程复杂性高、开发周期长,而完全采用C语言编程则程序的执行效率相对较低,不能满足实时性的要求。为了设计出性价比最好、开发周期较短、比较复杂的DSP系统,可以采用混合语言编程,把C语言和汇编语言的优点有效地结合起来。C语言和汇编语言的混合编程有三种形式:在编写C语言代码中插入汇编语句只需在汇编语句两边加上双引号和括号,在括号前面加上标识asm,如asm“汇编语句”;在编写C代码的过程中调用内联函数TMS320C62X中有一些直接映射为内联的C6000指令的特殊函数,内联函数用前下划线_表示,使用时同调用C语言的库函数一样调用它,如b=_nassertN>=10;汇编代码以C代码可以调用的函数出现。本文采用第三种形式。为了使程序代码的执行具有尽可能高的执行效率,本文将着重点放在并行汇编代码的编程,而不是线性汇编代码的编程。
1 C语言与汇编语言混合编程的接口规范和标准
用C语言编写的代码中核心代码常常只是整个程序代码的5%,但是却占用了整个程序约95%的执行时间。对这些核心代码采用汇编语言编写,可以大大提高代码的执行效率,而C语言程序可以象调用C程序的一个函数那样去调用这个汇编函数。为了实现C语言和汇编语言的混合编程,需要注意一些规定的接口规范和标准。
(1)采用C语言和汇编语言混合编程时,TMS320C62X定义了一套严格的寄存器规则。这个寄存器规则表明了编译器如何使用这些寄存器以及在函数调用过程中如何保护这些寄存器。
调用函数保护了寄存器A0~A9和B0~B9,这就使得在编写汇编程序的时候可以任意的使用这几个寄存器而不需保护它们。但当使用到寄存器A10~A15或B10~B15的时候,则必须自行对它们进行保护。长型、双精度型或者是长双精度型的数据对象要放在一个奇/偶寄存器对(如A1:A0)里,奇数寄存器存放着数据的符号位、指数位和最高有效位,而偶数寄存器则存放着低有效位。
在默认情况下,A3用作返回结构指针寄存器,B3用作被调用函数返回地址寄存器,A15用作帧指针寄存器,B14用作数据页指针寄存器,B15用作堆栈指针寄存器。这些寄存器在被调用的汇编函数中用到时都要进行保护。
(2)调用函数将参数传递到被调用函数中,前十个参数将被从左到右依次放入寄存器A4、B4、A6、B6、A8、B8、A10、B10、A12和B12,如果传递的参数是长型、双精度型或者是长双精度型,则将参数依次放入寄存器组A5:A4、B5:B4、A7:A6等,并将剩下的变量按相反的顺序放在堆栈里。注意,如果传递的参数是一个结构类型的参数,则传递的是该结构类型的地址。
(3)如果在C/C++调用函数中做了正确的函数返回声明,则被调用的汇编函数可以返回有效值。如果返回值是整型或32位的浮点型,则放在寄存器A4中返回;如果返回值是双精度或是长双精度型,则放在A5:A4中返回;如果返回值是一个结构类型,则将其结构的地址放在A3中返回。
(4)编译器为所有的外部对象指定一个链接时的名字。当写汇编语言代码时,必须用与这个名字相同的名字。对于只在汇编语言模块中用到的变量的标识符,不能从下划线开始。任何一个在汇编语言中声明的对象都要使其在C/C++中是可访问的,那么在汇编语言中必须用.def 或.global将其声明为外部变量。同样在汇编语言中要引用C/C++函数或对象时,必须用.ref 或.global将C/C++对象声明,这将产生一个在汇编语言函数中没有定义的由链接器辨识的外部引用。
还有一些细节也需要注意,如中断子程序必须把该子程序将要用到的所有寄存器进行入栈处理;除了全局变量的初始化外,汇编语言的模块不得因为任何目的而使用.cinit段;汇编代码的结束需用指令B.s2 B3将程序执行从被调用函数返回到C语言调用函数中。
2 并行汇编代码的编写
C6000的汇编代码格式如下:
标号: 并行标记 条件寄存器指令助记符 功能单元 操作数 ;注释。如:
LDW .D2 B4,B2
|| A1SHL .S2X A4,B4 ;用到了交叉数据通道
TMS320C62X片内有8个并行的处理单元,分为相同的两组。其体系结构采用超长指令字(VLIW)结构,一个指令包里的8条并行指令可同时分配到8个处理单元并行运行。这种一个指令包里有8条指令并行执行也给并行汇编代码的编写带来很多要考虑的问题具体如下:
(1)TMS320C62X指令的执行可以用延迟间隙来说明。延迟间隙在数量上等于从指令的源操作数被读取到执行的结果可以被访问所用的指令周期。如对于乘法指令(MPY),源操作数从第i个周期被读取,则其计算结果在第(i+2)个周期才可用。
(2)使用相同功能单元的两条指令不能被安排为并行指令。
(3)使用同一条交叉通路的两条指令不能被安排在同一个执行指令包中,这是因为从寄存器组A~B或者从B~A都只有一条交叉通路。
4将数据读入到(或存储自)相同寄存器组的两条读(写)指令不能被安排在同一个执行包中。
(武汉铁路职业技术学院 湖北 武汉 430205)
摘 要:对C语言的有关方面展开分析,介绍了C语言的基本程序形式、C语言中的语句分类、C语言与其他许多语言相比具体有什么特点,C语言的开发基本流程、C语言常见的错误简析及修改。最后对学习C语言给予总结和提示。
关键词 :C语言;语句分类;C语言流程;常见错误
中图分类号:TP312 文献标识码:A doi:10.3969/j.issn.1665-2272.2015.10.048
收稿日期:2015-03-16
1 初识C语言程序
从这个简单的C程序可以看出,C程序结构由头文件、主函数、系统的库函数组成,但程序功能不能,C程序的组成也有所不同,有时需要自定义函数来完成必要的功能。其中main主函数时每个C语言程序都必须包含的部分,而且main主函数的位置在程序中是任意的。
2 C语言的特点
与其他许多语言相比,C语言的特点有:①语言简洁灵活。C语言只有32个标准关键字,9种程序控制语句,程序书写形式自由;②数据类型和运算符十分丰富。既有系统定义的简单类型:整型、实型、字符型等。又有用户自定义的构造类型:数组类型、结构体类型、共用体类型等;③数据结构丰富。C语言提供了整型、实型、字符型等基本数据类型外,还提供了用基本数据类型构造出的各种复杂的数据结构,如数组、结构体、共用体等。另外,C语言还引入了与地址密切相关的指针类型,使得C语言的计算功能、逻辑判断功能非常强大;④允许直接访问物理地址。C语言中的位运算和指针运算符能够直接对内存地址进行访问操作,可以实现汇编语言的大部分功能。即直接对硬件进行操作;⑤它提供了大量的库函数供调用。简化了程序设计工作;⑥生成目标代码质量高。一般只比汇编生成的目标代码效率低10%~20%。C语言提供了一个相当大的运算符集合,而且其中大多数运算符与一般机器指令一致,可直接翻译成机器代码,因此,保证了C语言编写的程序生成的代码质量高,从而带来了编译和执行的高效率;⑦用C语言写的程序可移植性好。C语言提供的与硬件有关的操作,如数据的输入输出等,都是通过调用系统提供的库函数来实现的。库函数本身不是C语言的组成部分,因此用C语言编写的程序能够很容易的从一种计算机环境移植到另一种计算机环境中;⑧C语言学习难度较大。特别是指针、地址、函数调用等内容较难度大,需要认真学习才能掌握。
3 C语言程序的开发流程
从编写一个C语言源程序到得到最终的结果一般需要经过4个基本步骤:程序编辑、程序编译、程序链接、程序运行(见图1)。
4 C语言常见错误及分析
4.1.1 遗漏分号出现的错误
这个错误一般常出现在初学者所编程序中。
5 结论
C语言程序设计是一门强调实践练习的课程,没有捷径可走,只有不断地实践、练习、发现问题,不断解决问题,才能孰能生巧,举一反三才能将所学知识巩固发挥,最终掌握结构化程序的精髓,独自编写优秀高效的C语言程序。
参考文献
1 孙丽云.C语言程序设计教程[M].北京:化学工业出版社,2013
2 王立. 二级C语言程序教程[M].武汉:华中科技大学出版社,2014
关键词:C语言;文件处理;程序
中图分类号:TP312文献标识码:A文章编号:1009-3044(2010)17-4711-03
Based on C Language Program of the Realization of File Processing and Analysis
YU Min
(Changzhou Liu Guojun Vocational Technology College,Changzhou 213000, China)
Abstract: Using read and write technical of C language, you can read data from a disk file to the computer memory, after processing the data or intermediate results still can output to disk file permanent preservation. This article by "rating of handling procedures" as an example, this paper expounds the C language file processing method and process of the general.
Key words: C language; file handling; program
C语言具有较强的文件处理功能。C文件是典型的流式文件。在c语言中,文件被视为一个字符的序列,是由一个一个字符的数据顺序组成,而文件的存取是以字符为单位。根据数据的组织形式,C文件可分为文本文件(ASCⅡ文件)和二进制文件。
运用C语言,可以编制程序实现对一个已经存在的记录文件中的数据进行处理,结果信息既可显示到屏幕终端,也可再次保存到磁盘文件中去。本文以“评分处理程序”的实现为例,阐述了C语言文件处理的一般流程和方法。
1 需求分析
某竞赛活动,聘请十位专家作为评委为八位参赛选手进行现场打分,现已将选手的评分存于文本文档score.txt中,试以此为原始数据,去掉一个最高分和一个最低分后取余下分数的平均分,作为每位选手的最终得分并按此由高到低排名后存入文本文档result.txt中。
1.1 处理流程
事务处理流程(不包括数据处理的具体过程)如图1所示。
1.2 具体任务
1) 从文本文件score.txt中(如图2所示),按格式读出原始数据显示到屏幕,求出每位选手的总分存total数组中并显示到屏幕。
2) 找出每位选手的最高分和最低分后显示到屏幕。
3) 总分去掉一个最高分和一个最低分后取余下分数的平均分作为每位选手的最终得分仍存total数组中并显示到屏幕。
4) 按最终得分由高到低排名后存入文本文件result.txt中(如图3所示)。
2 源文件分析
在文本文件score.txt中,以记录的形式存放了十位评委对八位参赛选手的打分。每行记录均按选手编号,选手姓名和十位评委的打分依次存放,且编号和姓名为字符,评委打分为保留二位小数的实数。如何将数据从文件读取到内存中?如何存放?根据前面介绍,C文件可视为由一个个字符数据顺序组成的字符序列。则可选用fscanf函数,从此文件流中执行格式化输入,将编号、姓名和分数按不同的格式读入到内存。读入后,可将八位选手的编号(三位字符)存放在二维字符数组number[8][4],姓名(不超过四个汉字即八个字符)存放在二维字符数组name[8][9],十位评委的打分则存放在二维实型数组score[8][10]中待处理。为方便读者理解数据读入前后在文件与内存中的存放形式,将score.txt文件内容划分成三大块对应内存中的number,name和score数组。
3 程序设计与实现
用C语言实现评分处理程序,使其具有读源数据文件、求总分、平均分、最高分、最低分、排序和写结果文件等功能。
3.1 序设计思路
C语言是面向结构的程序设计语言,且C程序是由函数构成的。根据功能设计本程序的函数包括:主函数main( )、读文件函数readfile( ) 、数据处理函数dealscore( ) 、求最高分函数max( ) 、求最低分函数min( ) 、排序函数getorder( )和写文件函数writefile( )。各函数间通过函数调用实现功能的整合,其中主函数分别调用读文件函数、数据处理函数、排序函数和写文件函数;数据处理函数再分别调用求最高分函数和求最低分函数。
3.2 程序流程图
本程序的执行流程如图4所示。
3.3 程序实现方法
1) 主函数:按一定顺序调用各功能函数,串起整个程序,实现本程序功能。
2) 读文件函数:主要实现从给定文件中读取数据存数组并按格式显示到屏幕。首先定义文件指针fpscore,再利用fopen函数打开文件,由于score.txt为文本文件,则选用“r”方式打开。然后读文件存相应数组,C语言中读文件的函数较多,有读入单个字符函数fgetc、读入字符串函数fgets、读入数据块函数fread(一般适用于二进制文件)和格式化读入函数fscanf。根据前面介绍的源文件分析及数据处理的要求,选择使用fscanf函数进行格式化读入,并且存入不同类型和大小的数组:number,name和score。fscnaf函数的原型是:fscanf(文件指针,格式字符串,输入表列);其中文件指针即为fpscore,格式字符串中依次为%s,%s和十个%f及\n,分别控制输入表列中的number[k],name[k]和score[k][0]~ score[k][9],按行循环地读入,其中k指第k位选手,每读完一行选手的数据,变量k就累加一次,故当本程序段执行完后,k正好为选手的人数。循环可利用while语句实现,只要不到文件末尾就读文件,关于是否已读到文本文件末尾,可用EOF判断或feof函数测试,此处用feof函数测试实现较为方便。最后利用fclose函数关闭该文件。
3) 数据处理函数:主要实现求每位选手的最终得分。首先利用for循环求出每位选手的十位评委的评分之和存入total数组,再调用max( ) 和min( )函数求出每位选手的最高分和最低分,最后按总分去掉一个最高分和去掉一个最低分后求平均的方法求出每位选手的最终得分。并将这些中间结果显示到屏幕,如图5所示。
4) 求最高分函数:主要实现求某位选手的最高分。函数为有参函数,形式参数为minscore[10],接收dealscore( )函数中实际参数score[i]的值,两者类型一致,且score[i]其实表示第i位选手的十个评分,故大小也一致,可以实现数据的传递。然后利用比较法求出一组数中的最大值即为最高分。最后用return语句返回最高分给主调函数待处理。实现代码如下:
/*求最高分函数*/
float max(float maxscore[10])
{int i;
float max=maxscore[0];
for(i=1;i
if(maxscore[i]>max) max=maxscore[i];
return(max);}
5) 求最低分函数:主要实现求某位选手的最低分。方法与求最高分类似,就不做说明。
6) 排序函数:主要实现将数据按最终得分由高到低排序。排序算法选用冒泡算法,算法中数据交换的条件是前一最终得分小于后一最终得分,值得注意的是:编号和姓名均为字符串,C语言中字符串的交换必须使用字符串处理函数strcpy()实现。另外,除了交换编号、姓名、最终得分外还需依次同时交换该相邻两位选手的十个评分,否则score数组中的数据将混乱。
实现代码如下:
/*排序函数*/
void getorder(char num[100][4],char xm[100][9],float cj[100][10],float sum[100],int t)
{int i,m,n;
char x[4],y[9];
float s,f;
for(m=1;m
{for(n=0;n
if(sum[n]
{strcpy(x,num[n]);strcpy(num[n],num[n+1]);strcpy(num[n+1],x);
strcpy(y,xm[n]);strcpy(xm[n],xm[n+1]);strcpy(xm[n+1],y);
for(i=0;i
{f=cj[n][i];cj[n][i]=cj[n+1][i];cj[n+1][i]=f;}
s=sum[n];sum[n]=sum[n+1];sum[n+1]=s; }}}
7) 写文件函数:主要实现将最终结果写入文本文件result.txt中。首先定义文件指针fpdkdz,再利用fopen函数打开文件,由于result.txt为文本文件,则选用“w”方式打开。然后将名次、编号、姓名、得分依次写入文件,C语言中写文件的函数也较多,有写入单个字符函数fputc、写入字符串函数fputs、写入数据块函数fwrite(一般适用于二进制文件)和格式化写入函数fprintf。根据要求选择使用fprintf函数进行格式化写入,每写完一位选手的结果就换一行。其中名次可用计数器i依次累加实现。最后利用fclose函数关闭该文件。
4 结论与分析
C语言中文件处理的一般步骤可归纳为:先利用fopen()函数配合恰当的使用方式打开文件,再选择适当的读写函数读写文件,最后切记一定要利用fclose()函数关闭该文件,以避免意外的发生。
笔者认为C语言文件操作时还应特别注意区分文本文件与二进制文件,根据文件类型和具体要求选择合适的文件使用方式。另外,在读写文件尤其是读文件时还应关注文件的位置指针,必要时可使用rewind()函数重定位或fseek()函数移动位置指针,进行随机读写。
C语言文件处理较为实用,许多可供实际使用的C程序中都包含文件处理,掌握好文件的使用,还需更多的实践和探索。
参考文献:
[1] 谭浩强.C语言程序设计[M].北京:清华大学出版社,2005.
关键词: Fortran 90;接口块;C++;面向对象程序设计;函数重载
中图分类号:TP314 文献标识码:A 文章编号:1671-7597(2011)1210193-02
0 引言
面向对象方法更加符合人类思维习惯,在软件开发中被公认为是能够提高代码重用性和可维护性的有效方法。C++支持面向对象程序设计,其函数重载机制可以提高程序设计的可读性和灵活性,是面向对象程序设计的一个常用方法。
Fortran语言是最早诞生的高级语言,广泛应用于科学与工程计算领域。与Fortran 77相比,Fortran 90增加了模块、自定义类型、指针、接口块等新工具[1],使其具有了一些现代语言特征,但仍是面向过程的编程语言,不直接支持函数重载等面向对象程序设计[2]。
本文利用Fortran 90新提供的接口块等工具,对C++函数重载进行模拟,并通过实例进行验证。C++开发环境为Visual C++ 6.0,Fortran 90开发环境为Compaq Visual Fortran 6.6。
1 函数重载
1.1 函数重载现象
数学上求一个数的绝对值,这个数既可以是整数也可以是实数,所调用的是同一个函数。假如用C语言编写一个求绝对值的函数,由于参数的数据类型不同,需要定义两个不同名称的函数,分别对整数和实数进行求值:
Int iabs(int);float fabs(float);
尽管这两个函数都是实现求绝对值的功能,函数名称却不同,这与人们的日常思维习惯不符,给程序设计人员记忆和使用函数带来不便。针对此类问题,C++则通过函数重载来解决[3]。函数重载是指在同一作用域内,用相同的函数名对应不同的函数实现,这些不同实现的同名函数称为重载函数。例如,C++可以将求绝对值的函数定义成一组函数名相同的重载函数:
int abs(int);float abs(float);
在调用程序中,由C++编译器根据实参和形参的匹配,自动选择调用哪一个重载函数。被重载的函数须同时满足以下条件:
1)要有两个或两个以上,且在同一作用域内;
2)实现的功能必须相同,函数名必须相同;
3)至少要在参数类型、参数个数或参数顺序上有所不同,即参数表不同。
C++函数重载包括类成员函数重载和普通函数重载,二者在本质上是相同的,都是函数名相同参数表不同。故此,本文以普通函数重载为例进行说明。
值得注意的是:C/C++与Fortran同属编译型语言,其实现例程(函数和子程序统称为例程)的机制相同,Fortran有返回值的例程为函数(Function),无返回值的例程为子程序(Subroutine);C/C++中
类型的函数无返回值,其它类型的函数有返回值,分别与Fortran中的子程序和函数对应。换言之,C++中的函数重载实际包括Fortran中的函数与子程序二种例程的重载。
1.2 函数重载的实现
在C++中,以交换两个整数和两个实数为例分析函数重载的实现。
#include
void swop(int & x, int & y) // 定义重载函数,参数以引用方式传递
{ int t; t = x; x = y; y = t; }
void swop(float & x, float & y) // 定义重载函数,参数以引用方式传递
{ float t; t = x; x = y; y = t; }
void main( void ) // 主函数
{ int a = 3, b = 4; float c = 2.5, d = 6.9;
swop(a, b); cout
swop(c, d); cout
其中,用同一函数名swop分别定义了两个参数表不同,功能相同的重载函数。在主函数中,分别调用重载函数swop对整型数a、b和实型数c、d进行交换,程序运算结果为a=4;b=3与c=6.9;d=2.5,实现了正确调用。从而证明:C++编译器能够根据参数表匹配的原则,自动判断并选择调用合适的重载函数。
实质上,C++编译器在编译重载函数时,会依据参数表的不同给目标重载函数添加不同的修饰,依此来对重载函数加以区分。这样,才使得函数重载机制得以成立。
2 模拟函数重载
2.1 模拟手段-接口块
在C/C++语言程序中,通常使用头文件作为调用程序与系统库函数之间的桥梁和纽带。头文件中描述了各个系统库函数的函数名、返回值类型与参数列表等接口信息,但其本身并不包含库函数的实现代码。用户调用库函数时,由编译器按照头文件中的函数原型从相应库中提取库函数的实现代码参与运算。
Fortran 90新增加的接口块具有与C/C++头文件类似的作用,可以在调用程序中通过接口块明确被调外部例程的接口信息,如例程是函数还是子程序、例程名、函数返回值类型、参数的个数、传递方式及其数据类型等,这样,调用程序就能对外部例程产生正确调用。
假如不使用接口块,我们用Fortran 90外部例程(子程序)实现一个简单算法:
Subroutine PrintReal (x)
Implicit None ! 废除Fortran 77的隐含声明,即I-N规则
Real x
Print*, "x = ", x ! 将参数x(实型)输出到屏幕
End Subroutine
调用该外部例程的主程序为:
Program Main
Implicit None
External PrintReal ! 声明PrintReal为外部例程
Integer :: a = 1.0
Call PrintReal(a) ! 调用PrintReal外部例程
End Program
程序编译、链接都没问题,但程序运行结果为x=1.4012985E-45,显然是错误的。原因是形参x的数据类型为实型,对应实参a的数据类型却为整型,实参与形参的数据类型不匹配,从而导致调用错误。假如我们在主程序中建立被调外部例程PrintReal的接口块,来替换External PrintReal语句:
Interface
Subroutine PrintReal (x)
Real x
End Subroutine
End Interface
程序编译时就会提示错误:实参与形参的数据类型不符,这也正是我们希望看到的结果,从中也看到了在调用程序中建立被调外部例程接口块的重要性。
在外部例程接口简单的情况下,调用程序中是否建立被调外部例程的接口块是可选的;但在下列情况下必须使用接口块[4]:
1)外部例程具有可选参数;
2)外部函数返回数组或变长字符串;
3)外部例程具有假定形状数组、指针或目标参数;
4)例程做参数。
接口块的构造形式为:
Interface
接口体
End Interface
当中的接口体,类似于C/C++中的函数原型声明,只包括外部例程的接口信息。通常,接口块位于调用程序的声明区。
探索中发现,当接口块只声明一个外部例程原型时,若给接口块命名,则在调用程序中可以用接口块名代替外部例程名进行调用;当接口块中声明两个或两个以上外部例程原型时,还能否用接口块名代替外部例程名,依据参数表匹配的原则,选择调用合适的外部例程呢?如果这种设想成立,就可以用Fortran 90模拟C++函数重载。
2.2 实现模拟
上述探讨的Fortran 90接口块,主要针对的是外部例程,通过在调用程序中建立其接口块,明确其接口信息,来产生正确的调用。若将外部例程置于模块(Module),则外部例程就转化为模块例程。因此,例程重载分外部例程重载和模块例程重载二种。
2.2.1 外部例程重载
以交换两个整数和两个实数的重载为例,重载的外部例程实现分别为:
Subroutine SwopInteger (x, y)
Integer temp, x, y
temp = x; x = y; y = temp
End Subroutine
Subroutine SwopReal (x, y)
Real temp, x, y
Temp = x; x = y; y = temp
End Subroutine
在调用程序的声明区建立如下的接口块:
Interface Swop ! 建立有名接口块
Subroutine SwopInteger (x, y) ! 声明重载外部例程接口
Integer x, y
End Subroutine
Subroutine SwopReal (x, y) ! 声明重载外部例程接口
Real x, y
End Subroutine
End Interface
这样,就可以用统一的形式Call Swop(a,b)分别调用两个不同的外部例程:当实参a和b为整型时,调用的是SwopInteger外部例程;当实参a和b为实型时,则调用的是SwopReal外部例程。从而,成功地模拟了C++函数重载机制。
2.2.2 模块例程重载
将上述二个外部例程置于模块,转化为模块例程(Module procedure):
Module MyMod ! 模块程序单元
Implicit None
Contains
Subroutine SwopInteger (x, y) ! 重载的模块例程
……
Subroutine SwopReal (x, y) ! 重载的模块例程
……
End Module
由于模块的缺省访问属性为Public,所以一旦调用程序引用(Use)了模块,模块中包括模块例程在内的实体在调用程序中就是可见的,模块例程就如同调用程序的内部例程,其接口是自显的[5]。所以,建立模块例程重载的接口块可以只列出重载的模块例程:
Interface Swop ! 定义模块例程重载接口块
Module procedure SwopInteger, SwopReal
End Interface
正因为模块的缺省访问属性为Public,所以模块例程重载的接口块既可以置于模块的声明区,也可以置于引用模块的调用程序的声明区。程序运行结果表明,模块例程同样可以被重载。
3 结语
Fortran 90不支持面向对象程序设计,但具备了一些现代语言特征,本文正是利用其提供的接口块这一利器,对C++函数重载进行了成功模拟,给出了外部例程和模块例程两种重载方法,为Fortran 90的应用扩展积累了经验。
参考文献:
[1]ISO/IEC 1593-1:1991,Fortran 90[S].
[2]周振红、余明辉、张成才等,Fortran 90模拟C++主要面向对象特性[J].武汉大学学报(工学版),2006,39(2):42-46.
[3]吕凤翥,C++语言程序设计[M].北京:电子工业出版社,2006:113-114.
[4]周振红、郭恒亮、张君静等,Fortran 90/95高级程序设计[M].郑州:黄河水利出版社,2005:28-29.
[5]任慧、周振红,Fortran与C/C++共享模块中的数据和例程[J].郑州大学学报(工学版),2008,29(1):99-101.
Fortran 90 emulating C++ function overloading
JIN Kaiguan, ZHOU Zhenhong
(School of Hydraulic & Environmental Engineering,Zhengzhou University,Zhengzhou 450001,China)
Abstract: Function overloading is an important embodiment of polymorphism in C++, and a kind of common use for object-oriented programming. Fortran 90 does not support object-oriented programming, but possesses some features of modern computer languages which make it possible to emulate object-oriented programming. With the exploration of some related language elements and tools of Fortran 90, it is put forward that the function overloading mechanism can be emulated indirectly with the new powerful tool of interfaces on the basis of analyzing C++ function overloading. The examples have proved that this method is workable so as to extend the applicable areas of Fortran 90, and provide some ideas to emulate object-oriented programming.
Key words: Fortran 90;interface;C++;object-oriented programming;function overloading
关键词:System Verilog;芯片模拟器
中图分类号:TP311文献标识码:A文章编号:1009-3044(2012)07-1662-03
Design and Implementation of Chip Simulator Based on System Verilog
WANG Yuan1, CHEN Meng-dong1, CHEN Dong2, LIU Yang2, QI Peng2
(1.Jiangnan Institute of Computing Technology, Wuxi 214000, China; 2.65587 Army, Siping 136000, China)
Abstract: This paper introduces the interface between System Verilog and C, and describes the basic method of data sharing between two languages. Through the functional analysis of a sample chip, we design four interface functions of the chip simulator and describe their implementation. We can learn about the realization of chip simulator on System Verilog platform through this paper.
Key words: System Verilog; chip simulator
1概述
在当今百万门级的ASIC设计中,验证所占用的时间无疑成为缩短集成电路产品设计周期中的瓶颈。如何改进验证方法,改善验证手段,从而提高验证效率,缩短验证周期,是验证人员乃至产品经理们最关心的问题[1]。System Verilog结合了来自Verilog、VHDL、C++的概念,以及验证平台语言和断言语言,将硬件描述语言HDL与现代的高层级验证语言HVL结合了起来,使原本繁琐费时的验证工作变得相对简单易行。与传统的验证方法相比,这种验证方法大大提高了验证工作的效率,缩短了验证的周期,同时有力地保证了验证的完备性。
同时,System Verilog提供了与其他语言的编程接口,可以通过和其他语言数据共享的方式进行相互交互,将验证工作中的繁琐复杂的功能交给软件来实现,提高验证的效率和性能。这样在芯片的验证过程中,就可以通过数据共享将芯片的主要功能通过软件来实现,然后通过比对结果来验证芯片功能的正确性。
2 System Verilog与C语言接口介绍
Verilog使用编程语言接口(PLI, Programming Language Interface)来跟C语言交互,相比之下System Verilog引入了直接编程接口(DPI, Direct Programming Interface),它能更加简单的连接C、C++或者其他非Verilog编程语言[2]。
一旦声明或者使用import语句“导入”了一个C子程序,就可以像调用System Verilog中的子程序一样来调用它。import声明定义了C任务和函数的原型,但使用的是System Verilog的数据类型,带有返回值的C函数会被映射成一个System Verilog函数,void类型的C函数则被映射成一个System Verilog任务或者void函数。导入的C子程序可以有多个参数或者没有参数,缺省情况下参数的方向是input,即数据从System Verilog流向C函数,但是参数的方向也可以定义为output和inout。
通过DPI传递的每个变量都有两个相匹配的定义,一个是System Verilog的,一个是C语言的,这里需要确保两者使用的是兼容的数据类型。由于数据类型比较繁杂,为了说明两者之间数据类型的对应关系,以下就System Verilog和C语言之间的数据传递进行简单介绍。
2.1数据类型映射
表1给出了System Verilog和C语言子程序输入输出之间数据类型的映射关系,C结构类型在头文件svdpi.h中定义,在使用时需要包含此头文件。
在使用两种语言进行对接交互的时候,函数参数和返回值的数据类型参照上表进行相应转换即可保证两者的数据是兼容并可以互相通信使用的。
2.2开放数组
当需要在System Verilog和C之间共享数组的时候,可以采用反向工程的方式分析出数组在System Verilog中的存储方式,而在C中根据数组的内存映射方式进行操作。然而这种方式很容易出错,一旦任何一个数组有变化,必须重新编写代码进行调试。在System Verilog中提供了“开放数组(open array)”来处理这种情况,这使得我们能够编写出可以操作任何大小数组的通用C代码。在System Verilog中开放数组的查询函数比较多,这里笔者就基本的开放数组的使用方法进行简单介绍。
使用基本的开放数组在System Verilog和C程序之间传递数据时,在System Verilog中声明相应的C函数,然后在C代码中可以使用svOpenArrayHandle类型的句柄来引用此开放数组。该句柄指向一个含有字范围等开放数组信息的结构,可以通过调用svGetArrayPtr等方法来获取实际的数组元素,该函数返回一个void*类型的指针。
2.3复合类型
对于C和C++中比较复杂的类,就类属性的内存映射方式来讲,两种语言并不完全一致,不能直接共享对象。为了达到共享的目的,System Verilog测试平台使用压缩结构来保存一个简单的像素,使用类来封装对像素的操作。通过使用压缩和解压缩的方法对两种数据格式进行转换,就可以使两者共享符合类型的数据了。
3芯片模拟器的设计与实现
通过以上介绍,笔者针对芯片的整体架构及功能,采用上述的System Verilog与C对接的方式对芯片模拟器整体架构及主要功能模块的设计和实现进行详细说明。
3.1芯片模拟器整体架构
在基于System Verilog与C对接的模拟器实现中,System Verilog作为整个验证环境的平台,将测试数据分别发送给芯片的硬件逻辑和芯片模拟器,然后收集两者的数据输出结果进行比较,以期判断芯片逻辑的正确与否[3],具体的结构如图1所示。
图1
其中,芯片模拟器采用软件的方法实现了芯片逻辑需要验证的功能,并根据整个验证平台的需要添加需要的辅助功能。为了更直观的介绍芯片模拟器的设计和实现,这里以笔者实现的一个简单芯片模拟器为例进行说明。
此芯片的主要功能可以简化为发送、接收数据以及配置芯片参数这三个简单的功能,芯片模拟器的功能则是在这三个接口上对芯片的功能进行模拟实现,然后比对相应的数据是否正确。其中发送方向上对测试数据进行处理然后发送输出,接收方向则从接收方向对测试数据进行处理,配置芯片参数通过测试数据生成模块将参数发送给芯片模拟器进行配置。需要注意的是,为了验证芯片逻辑的正确与否,这里System Verilog平台发送给芯片逻辑和芯片模拟器的数据必须是完全相同的,这样才能保证通过结果比对得到的测试结果是有参考价值的。
通过以上分析,笔者将这三个主要功能分别进行实现,其中发送和接收数据两部分需要用到芯片参数配置部分所配置的芯片参数,因而这里将芯片参数设定为全局参数,方便芯片参数配置部分进行参数配置以及发送和接收数据时依照此参数进行数据处理。芯片参数配置设计一个单独的接口方便进行参数配置,同时,为了验证参数配置地是否正确,需要另外的接口来从全局参数中读取芯片参数来验证参数配置的正确性。发送数据方向设计一个接口来处理发送方向的数据,这里需要用到芯片的参数,通过以上的设计简单的读取全局芯片参数即可。接收数据方向同样设计一个接口来处理接收方向的数据,和发送方向类似,通过读取全局芯片参数进行数据处理。芯片模拟器的整体结构如图2所示:
图2
3.2配置接口
配置接口负责芯片参数的配置以及验证所配置参数的正确性。由于需要配置的参数比较多,这里通过地址译码的方式来进行配置;同样,读取芯片参数时也需要相应的地址来读取所需的芯片参数,基于此两个函数的结构就确定了。
配置芯片参数的函数接口如下:
int setReg(const svBitVecVal* addr, const svOpenArrayHandle data);
其中,返回值为1表示配置成功,返回0表示配置过程中出错;参数addr表示所配置参数在地址列表中的地址,参数data则为相应地址所配置的芯片参数值,这里data采用开放数组的方式来处理相应数据,为共享数据提供了便利[4]。为了能够调用此函数,在相应的System Verilog代码中需要导入此函数,具体如下:
import“DPI-C”function int setReg(input bit [7:0] addr, input bit data[]);
读取芯片参数的函数接口如下:
int getReg(const svBitVecVal* addr, const svOpenArrayHandle data);
类似函数setReg,返回值为1表示读取参数成功,为0表示读取失败;参数addr表示要读取参数的地址,data则是读出的芯片参数。同样,为了能够调用此函数,也需要在相应的System Verilog代码中导入此函数,具体如下:
import“DPI-C”function int getReg(input bit [7:0] addr, output bit data[]);
这里需要注意的是此处data的数据方向为output,因为这里是读取芯片参数,data的数据空间需要在System Verilog中先分配好[5]。
3.3发送方向
发送方向和接收方向的数据处理是芯片最主要的功能,此部分需要按照芯片逻辑所设计的功能进行模拟实现,这两部分中所用到的芯片参数已通过读取全局参数解决,其他部分只需用C语言来进行相应功能的实现即可。具体的函数接口如下:
int send(const svOpenArrayHandle data, const svBitVecVal* type);
其中函数返回值为1表示发送方向数据处理完成并成功发送,0表示发送方向出错;data即为需要处理的数据,type表示待处理数据的数据类型。System Verilog中导入此函数的方式如下:
import“DPI-C”function send(input bit data[], input bit [2:0] type);
在进行数据处理时只需要在相应的子函数中将data进行数据类型转换,使其能够在C语言中进行处理,这样就可以使用软件的方法对芯片功能进行模拟了。具体方法如下:
unsigned char* data_in = (unsigned char*)svGetArrayPtr(data);
通过函数将data转换为C语言中的指针类型,这样就可以通过指针访问System Verilog中的数据,实现System Verilog和C的数据共享,完成芯片相应功能的模拟。
3.4接收方向
接收方向的数据处理和发送方向类似,函数接口如下:
int recv(const svOpenArrayHandle data);
其中函数返回值为1表示接收方向数据处理完成,0表示接收方向出错;data即为接收的待处理数据。System Verilog中导入此函数的方式如下:
import“DPI-C”function recv(input bit data[]);
数据处理以及数据共享的实现和发送方向的处理类似,这里不再赘述。
4结论及下一步工作
本文首先介绍System Verilog和C语言之间数据交互的方法以及两者互相调用子函数的方式,然后通过笔者以该方式实现的芯片模拟器为例进行详细说明,以此方式来对整个芯片的功能进行验证,具有一定的普遍性。通过这种方式实现的芯片模拟器比较灵活,并且实现起来相对硬件描述语言简单,同时通过数据共享,能够对芯片功能的各个方面进行比较详尽的模拟,在芯片验证工作中具有非常出色的表现。
最后,需要指出,通过这种方式实现的芯片模拟器,在一些方面还存在着不足,在硬件更底层的模拟中还不能够完全取代其他验证方式;在一些比较特殊的情形中通过软件来模拟比硬件描述语言更为复杂,这也是此方法的不足;另外,笔者实现的芯片模拟器在芯片功能模拟时模拟程度还不是非常精确,需要后续的改进和完善。
参考文献:
[1]周卓.基于SV语言的802.11 MAC芯片逻辑验证方案[J].现代电子技术,2009(18).
[2] Chris Spear.System Verilog for Verification[M].Springer,2006.
[3] Janick Bergeron,Eduard Cerny,Alan Hunter,et al.System Verilog验证方法学[M].夏宇闻,杨雷,陈先勇,等,译.北京:北京航空航天大学出版社,2007.
汇编语言与C语言均属于编程语言,但是二者之间存在着根本上的不同。在开发软件的过程当中使用这两种语言混合程序设计的技术是一种有效的程序设计方法,不仅能够有效提升工作的效率,还可以提升程序的性能。本文主要介绍了汇编语言与C语言混合程序设计的方法,希望给二者之间更好的衔接提供一定技术方面的支持。
【关键词】汇编语言 C语言 设计技术 混合程序
汇编语言是一种面向机器的编程语言,运算速度快,在使用汇编语言的过程可以通过提高存储器运行速度来提升其存储空间,另外,汇编语言其控制作用力应用在硬件上也有着无法取代的优点。同时汇编语言也有着程度较高却复杂和移植性差等缺点,但是在实际的操作中,硬件还有精确定的过程中必须要用到汇编语言。C语言作为一种高级语言,其表达性以及灵活性还有开发性均较高的优势,因此为了更好的发挥汇编语言和C语言在开发软件中各自的优点,将两者有机的结合起来,取长补短混合编程更好的达到设计的要求,高质量的完成设计任务。
1 C语言程序设计技术方法
(1)可以在C语言程序之中确定汇编程序的常、变量。
(2)可以在C语言编程当中适当的增加语句编辑,保证实现C语言无法控制硬件的缺陷。
(3)然而使用C语言程序时可以通过内部函数的使用加入汇编语言中的相应语句。
2 汇编程序设计技术及方法
在C语言编程当中,可以将汇编语言的代码直接的编写进去,并且融入汇编语言的过程当中可以不使用分号,详细的语法是:
asm
若想要将一组汇编语句融入到C语言中,必须要将语句括到括号{}当中。
asm {
mov ax,dataA
xchg ax,dataB
mov dataA,ax
}
一般想要在C语言程序当中编入汇编语言,有四种类型,分别是一般指令、跳转指令、串联指令和局部定义指令。
汇编语言子程序应用在C语言中,一般情况下汇编语言的子程序其基本格式是:
MYCODE SEGMENT PARA PUBLIC‘CODE
PUBLIC_函数名;
公共符号说明DGROUP GROUP MYDATA,MYBBS
MYDATA SEGMENT WORD PUBLIC‘CODE’
...定义变量,初始化数据
MYDATA ENDS
MYBBS SEGMENT WORD PUBLIC‘CODE’
...非初始化数据,开辟内存区
MY BBS END
ASSUME
CS:MYCODE,DS:DGROUP,SS:DGROUP
...
_函数名 PROC NEAR/FAR
PUSH BP
MOV BP,SP
PUSH SI
PUSH DI
...程序主体语句
POP DI
POP SI
POP BP
RET
_函数名 END UP
...
MYCODE ENDS
END
3 C语言汇编语言需要调用其它子程序的语言格式
把被调用程序其格式和普通汇编语言程序分布情况加以比较能够发现:
因为C语言程序和进行汇编的子程序需要共用同一个程序运行区间,所以在刚刚开始进行子程序的C语言汇编时就需要运行PUSH BP和MOVE BO,SP这两个命令。
必须要把将会被修改和汇编到C语言程序中的子程序进行局部调用的PUBLTC操作,通过进行PUBLTC的操作来表示该段C语言子程序已经参与到其他的操作中,被其他程序所调用了。
虽然已经被调用的子程序会接受程序的控制,但也需要对该段子程序利用SI和DI进行局部变量的保存,但是仅在变量高于120分钟时,才能将其在堆栈当中加以存放。因此,这一模式进行过程中,我们可以清楚的看到PUSH DI还有PUSH SI的语句。
在经过汇编的程序C语言中,要把MYCODE的代码段、初始数据段、修改数据段进行分别的定义,并且把这几个分段的汇编程序组合成为一个有效段组,保证该段段组基址的共用性。
在汇编之后的程序语句之前必须要增加一段函数值语句,保证语句可以有效的返回,进行下一段的程序循环,并且设置的返回值要在RET语句的前方。
值得注意的是,不同意调用过的子程序必须要用RET的命令增加返回功能,并且在结束语句后编辑结束END。这个END语句代表的是最终的终止,没有相应的启动功能。
通过C语言子程序的汇编,可以有效的保证其调用功能,同时也节省了相应的程序编辑空间。例如在程序输入时,不用修改程序的进位制就能准确的进行数据的读取,也就是说参与汇编的C语言子程序在格式上不会有太大的改变,只需要在原本子程序的起始部位增加相应的语句就可以了。
EXTERN 函数名,主要作用是为了反应出这个函数是C语言的子程序,且是外部调用的、。原本的主程序语句,可以利用外部程序来实现原本语句的调用功能,具体的调用格式如下:CALL NEAR PTR 函数名,而在将C语言程序当做是子程序的过程中,只包含有C函数,并不需要EXTERN来进行进一步的说明。
4 连接两种语言
由于汇编语言和C语言二者均存在着一定的问题,通过将两种语言混合编程,能够弥补两种语言各自存在的不足,因此,下面阐述如何连接这两种语言。
4.1 传递参数
在调用C语言及汇编语言时,可能会存在汇编语言的参数传递问题,通常都是利用堆栈来进行传递,通常在汇编C语言的过程中,要把BP基址当作原数据的储存器,C语言的汇编参数全部储存在堆栈储存器当中,如果在需要使用储存参数时,可以把存储在堆栈当中的数据进行清除处理。
4.2 调用关系的确定
对于即将要调用的函数或者是过程,要在调用开始之前明确的说明,建立完整的调用关系,详细的说明被调用的子程序是属于那个外部过程当中的,并且被调用的子程序应用在什么模块当中。另外要根据调用模块和储存方式的不同,对被调用的C语言汇编子程序进行格式的确定,一般情况下被调用的在大模式下与原本程序类型基本相似,小模式下存在微小的变化
4.3 模块连接
原有的C语言模块想要和汇编C语言的模块进行准确的连接,就需要做到以下两点:
(1)原有C语言模块必须与汇编C语言模块的储存方式相同。
(2)要求汇编模块要遵守和C语言模块兼容的相同命名。
因为编译系统在编译C源程序的过程当中,将会在函数名以及变量名称的前面画有下划线,想要保证连接前后相同,全部被C语言调用的汇编子程序其标识符前面都要标记下划线。并且,想要使汇编语言的标识符在C语言当中能够看见,需要用PUBLIC来定义。要求汇编语言当中其C语言的变量以及函数,必须要在二者前面加上下划线,同时,要求汇编程序开头的所调用C函数以及变量必须要用EXTERN对其进行说明。
为了有效保证C语言及汇编语言二者混合情况下设计的程序标准,能够有效的实施,必须要保证主要参数在变成函数被调用的过程中具有有效的传递作用,并且要求针对程序设计具体的情况来确定两个语言之间相互调用的关系。
在C语言的程序当中包括六种储存形式,分别是微型和小型以及中型和金丑行,还有大型和巨型这六种储存的模式。通过这点我们可以知道,主要由空间的大小来区别储存模式。在这当中微型的储存模式其程序和蹲站都在同一段中,而小型的储存模式拥有数据以及代码段,详细的数量为同一个。如果想要混合编程,首先必须要保证这两个程序所使用的是一个储存模式,对于汇编语言来讲,Model表示程序当中用到的伪指令,之后需要连接的内容便是储存的模式,通常是上面所讲的储存模式当中的一种模式。若C语言程序所使用的储存模式是小型的,那么汇编语言当中就会表示成Model Small,并且在这个时候这两种程序使用的储存模式一定是相同的类型。因为小型储存模式将Near当做是基础指针,因此,这种储存模式其运行效率极高,所以说在实际混合编程的情况下,如果符合条件这种情况下最好选择小型储存模式。
在编译C语言的过程当中,在变量以及函数名称的下面将会添加下划线,为了保证连接的质量,调用子程序的过程当中,任何标识符其下方都应该添加下划线。站在C语言程序的角度去看,将会把所调用的对象其中实际的变量和函数作为伪命令,进而起到说明的作用。一般把命令放在函数和变量的外部。除此之外,由于想要保存汇编语言程序标示符的完整性,应该使用PUBLIC定义相应的标示符。
5 结束语
通过本文对汇编语言与C语言的混合程序设计技术的进一步阐述,使我们了解到在开发软件的过程当中使用这两种语言混合的程序设计的技术,能充分发挥两种语言各自的特点,扬长避短,大大提高了软件开发的效率,缩短开发的周期,达到事半功倍的效果。通过本文对二者之间混合程序设计技术的具体阐述,希望能够给使用汇编语言及C语言混合程序设计方面提供一定的帮助,对于我国软件开发方面起到促进的作用。
参考文献
[1]陈久娅.C语言与汇编语言的混合程序设计技术研究[J].电子制作,2013(04):61.
[2]康晶晶.汇编语言与C语言的混合程序设计技术[J].计算机时代,2013(06):1-2.
[3]印德彬.汇编语言与C语言的混合程序设计技术[J].电子技术与软件程,2015(02):254.
作者简介
杨波(1979-),女,侗族,贵州省凯里市人。理学学士学位。现为黔东南民族职业技术学院汽车与机电工程系讲师。主要研究方向为软件开发。
【关键词】DSP系统编程;main函数;LDF文件
由于DSP在开始工作之前需要对芯片的时钟和外设进行设置,并且DSP系统通常一旦启动,便开始执行重复操作,所以DSP的程序设计和Windows应用程序设计会有一些不同,大概可归纳为以下3点:设计思想的不同,并行执行的不同,时间可预测性的不同。
首先,在DSP的程序设计中,通常需要先对DSP和设备进行初始化,初始化完成后的程序为一个无限循环,在循环中判断不同的条件执行不同的任务,并通过DSP中断来处理一些特殊的情况,类似于Windows应用程序设计中的消息机制;另外目前的DSP中并没有Windows编程中的多线程,除了DMA可以和DSP运算同时进行外,其他的操作都是顺序执行的,例如在执行中断服务函数时,需打断之前的操作过程,保存之前的现场后再开始执行中断服务函数,在完成中断服务函数后再恢复现场,并顺序执行进入中断前的程序;最后,实时信号处理要求程序的执行时间是可预测的,以判断系统是否满足实时性的要求。高性能的通用处理器普遍采用了CACHE和动态分支预测技术,使得程序执行时间的预测变得很困难,而DSP的动态特性较少,可以较容易地预测程序的执行时间,且DSP中的循环操作不需要额外消耗时间,而是通过硬件来完成循环计数器的衰减和循环的跳转,这对提高含大量循环程序的数字信号处理算法的效率是很重要的。
一个典型的DSP程序工程通常是由连接描述文件(*.ldf),头文件(*h),C语言程序文件(*.C),汇编语言程序文件(*.asm)等组成的。其中连接描述文件(*.ldf)用于描述多处理器的存储器偏移量、共享存储区域和每个处理器的储存空间;头文件(*h)主要用于函数宏定义和变量定义;C语言进行设计(*.C)、汇编语言程序文件(*asm)用于编写控制DSP运行的程序。
在程序设计过程中,通常需要自行编写的是C语言程序文件(*.c)和汇编语言程序文件(*asm),其中大部分程序可以通过C语言进行设计,关键的子函数可以通过汇编语言来实现以提高运行效率。
图1给出了一个雷达信号处理系统中单个DSP工作的流程。
图中,在程序开始之前,有对DSP和外部设备的初始化,之后一旦判断到中断信号,就开始进入循环,处理接收到的雷达数字信号,处理完成将运算结果输出后便又开始检测中断信号,等待处理后续的数据。该流程是一个典型的DSP信号处理流程。
ADSP-TS01S的编程与一般DSP的编程大同小异,下文将从系统初始化、DMA的使用和中断的使用这3个比较典型的方面对ADSP-TS201S的程序设计方法进行说明。
根据上面的介绍,本文DSP系统编程的介绍主要包括以下几个方面:ADSP-TS201S中LDF文件的编写、系统配置与初始化函数的编写、main函数的编写、系统配置与初始化函数的编写、main函数的编写及典型处理流程等方面。
1、ADSP-TS201S中LDF文件的编写
LDF文件是ADSP-TS201S工程中不可缺少的一部分,它主要用于多DSP工程中多个处理器工程之间的链接描述。通常所使用的DSP工程都是一个工程对应一个处理器,因此LDF文件不需要做出修改。
而对于建立多处理器(MP)系统,则需要使用到LDF文件。
建立MP系统的第一步是使用链接器的多处理器功能创建一个多处理器工程和一个描述系统的LDF文件
其中LDF文件用于描述多处理器的存储器偏移量、共享存储区和每个处理器的存储空间。在书写MP系统的LDF文件时,必须考虑以下LDF命令:
①MPMEMORY{ },该命令定义了每个处理器在多处理器存储空间(MMS)中的偏移量。在多处理器链接过程中,链接器使用该偏移量来链接各个处理器。
②MEMORY{ },该命令可定义系统中每个处理器的存储空间。
③PROCESSOR{ }和SECTIONS{ },利用这两个命令可定义各个处理器,并可使用存储器定义将每个处理器的输出文件放置到程序段中。
④SHARED- MEMORY{ },当在系统中使用了外部共享存储器时,需要使用该命令。该命令能识别共享存储器项的输出,并生成驻留在MP系统的共享存储空间中的共享存储区的可执行文件(.SM)。
⑤SM文件由工程文件中的源文件(.ASM,.C或.CPP)产生,该文件包含有放置于外部共享存储器中的数据变量的定义。
⑥LINK-AGAINST(),该命令可解析多处理器存储空间中的符号,并命令链接器检查指定的可执行文件(.DXEs and .SMs),以解析局部没有解析的变量和符号,以及在MMS(也就是系统中其他处理器的内部储存器)中定义的表达式或变量。通常在LDF文件中,必须使用LINK_GAINST 0命令。
如果命令行中包括.SM和.DXE文件,则必须先放.SM文件,后面接着放其他.DXE文件,只有这样,链接器才能正确的解析变量。一个LDF文件中最多可以说明的处理数量是由处理器结构指定的(比如ADSP TS201最多支持8片)。应该注意的是,在同一个LDF文件中,VisualDSP++4.0尚不支持有不同结构的DSP混合使用(如ADSP-TS201S和ADSP21160混合使用)
2、Main函数及典型处理流程
DSP程序设计中,最核心的部分便是main函数的设计,DSP中几乎所有的信号处理工作都在main函数中完成。
通常地,要设计一个DSP系统,第一步便是根据系统的需求去设计好DSP系统所需完成的流程图,当DSP处理流程图设计完成后时,剩下的工作便是根据流程图,设计图中每一个单元所需的子函数,并在主函数main中逐个调用这些子函数以实现流程图中的功能。