邹倩倩 孙沛 杨冰 孙梦婕
【摘要】通过对C、C++、Fortran不同语言混合起来进行编程,利用各自在数字计算和可视化应用等方面的优势,达到优势互补,并对在C、C++、Fortran混合编程中经常遇到的一些问题及其处理方式进行研究,如字符串处理、文件读写处理、函数调用、数据结构的存储等。
【关键词】C;C++;Fortran;混合编程;字符串;文件读写;函数调用
对C、C++、Fortran不同语言混合起来进行编程,利用各自的优势,弥补各自功能的不足,如FORTRAN语言具有强大的科学数字计算功能,但绘图功能不强;而C、C++语言计算功能不强,但它具有良好的移植性和较强的图形功能,可将计算方式转变为数据输入简易、结果显示方便的Windows可视化应用程序,因此,在许多情况下,我们应该使用C、C++、Fortran等进行混合编程。在既要大量计算,又要图形处理的开发环境中,可以通过混合编程,达到优势互补。
1.混合编程开发平台及编译开发环境的选择
Fortran语言没有大小写之分,而Windows平台下的混合语言编程过程中大小写问题十分突出。考虑到编译器的差异,可以用以下方式进行跨平台编程的函数声明。C、C++编译器使用MicrosoftVisualC++6.0编译集成开发环境,Fortran编译器使用DigitalVisualFortran6.0编译集成开发环境。
VC++与FORTRAN的语言编译器同出自微软家族,且使用同一操作平台,因此在它们两者之间进行混合编程是完全可以实现的,但是必须充分考虑两种语言之间的接口问题,即在存储模式、语言约定、数据处理以及例程单位等方面的一致性问题。
存储模式的一致性。存储模式是指编译器应遵循的某种规则,这种规则是把程序的代码和数据装入存储器段中的一套预先制定的规则,它定义了编译器将代码和数据组织分段的方法,同时也规定了访问每段中代码和数据的寻址方法。一般来说PC机上有6种存储模式:微小模式(Tiny)、小模式(Small)、中模式(Medi-um)、紧凑模式(Compact)、大模式(Large)、巨模式(Huge)。对FORTRAN一般用大模式,而VC++至少是紧凑模式以上,因为FORTRAN采用段间或远程传址。
语言约定的一致性。混合编程时,要注意调用程序与被调用程序遵守同样的约定,不能发生冲突。这些约定包括命名约定、调用约定、参数传递约定和函数返回值约定。
命名约定,即在编程过程中相互匹配的标识符应保持一致。由于VC++语言严格区分大小写,而FORTRAN中不存在大小写问题,VC++中还存在类型说明及其它一些问题,如果命名约定在调用程序与被调用程序之间不一致,程序就不会成功地连接。FORTRAN的缺省方式使符号名在目标文件中变成大写,如果在VC++程序中调用一个使用FORTRAN缺省的FORTRAN子例程,在VC++中需用一个纯大写的名称来生成一个调用;当在VC++中用一个纯小写的名称来生成一个调用时,在FORTRAN程序中需用C和STDCALL属性将所有名称转换为纯小写的形式;在VC++中,当一个调用例程的名称以混合书写形式出现的时候,需使用FORTRAN的ALIAS属性来解决混合书写形式之间的命名冲突。
调用约定,指语言实现调用的规则及方法。调用约定可以从三个方面影响程序设计:首先是调用例程利用调用约定决定传递给另一个例程的自变量的顺序;其次是被调用的例程利用调用约定决定接收传递过来参数的顺序;第三是所有涉及堆栈这样一种数据结构的参数从椎栈中移去后,调用例程和被调用例程必须在调整堆栈的职责上取得一致。在VC++与FORTRAN语言混合编程时,两者之间的函数调用一般采用C与STDCALL调用约定。
假设一个C语言函数为voidcFunction(),那么只需要在它的头文件里面进行如下定义即可。
#ifdef_cplusplus
extern/C0void{
#endif
externvoid_stdcallCFunction();
#definecFunctionCFUNCTION
#ifdef_cplusplus
}
#endif
这样就可实现上述函数在Fortran或C++程序中的直接调用。
2.混合编程中的字符串处理
混合编程中经常会出现需要传递字符串的情况,而字符串的传递是一个较为麻烦的问题。在Fortran里,字符串是没有结束符的,但是有长度的概念,也就是说,编译器会给每一个字符串一个长度以控制,在Windows平台下用如下方法定义。
以C函数为例,定义如下。
voidmessag(char*msg1,int*where1,char*msg2,int*where2)
{
printf(/,,%sshouldbe%d,while%ssh-
ouldbe%d\n0,msg1,*where1,msg2,where2);
}
如果要在Fortran里调用的话,需要以下定义。
#ifdefinedULTRIX||SPARC||IRIS||LINUX||WIN32
#ifdefinedULTRIX||SPARC||IRIS||LINUX
externvoid_stdcallmessag(char*,int*,char*,int*,int,int)
#definemessag(s1,i1,s2,i2)messag_(s1,i1,s2,i2,strlen(s1),strlen(s2))
#else/*WIN32Platform*/
externvoid_stdcallmessag(char*,int,int*,char*,int,int*)
如果要用在C++中,需要如下定义。
#ifdef_cplusplus
extern/C0{
#endif
/*yourexterncode*/
#ifdef_cplusplus
}
#endif
Fortran里便可以直接调用如下。
CALLMESSAG(char1,i1,char2,i2)
同样,在Fortran里写的字符串处理函数使用以上的define和extern后,也可以在C里直接调用。
3.混合编程中的文件读写处理
文件读写也是混合编程中一个非常重要的问题,由于编程语言的差异,不同的编译器的存储格式也存在差异,如VisualFortran与DigitalFortran在存储数据块中还存在着差别。在一个write语句中,VisualFortran存储数据块的开始标志与结束标志是用一个字节表示,而在DigitalFortran是用一个整形数,即4个字节来表示。也就是说,VisualFortran一个数据块最多可以存储128个字节,如果一个write语句要求写入的数据量大于128字节时,则按循环形式存入。所以,DigitalFortran在读取时就应该把它转化为相应的DigitalFortran存储形式。
4.混合编程过程中数据结构的处理
主要体现在数组和结构2个方面。在Fortran语言里,数组和C、C++里的数组有些不同,这表现在行列顺序和数组起始值.Fortran语言不同于C、C++的行优先,而使用列优先的方式。假设有一个数组a,m行n列,采用行优先时的数据存放格式如下。
a11,a12,a1n,a21,a22,,,a2n,,,
am1,am2,,,amn
而采用列优先的数据存放格式如下。
a11,a21,,,am1,a12,a22,,,am2,,,a1n,a2n,,,amn
行优先顺序推广到多维数组,规定为先排最右的下标;列优先顺序推广到多维数组,规定为先排最左的下标。这样,在混合语言编程里调用数据时必须注意行列优先的差别,进行准确地调用.数组的另一个差别是起始下标的不同。Fortran默认的数组下标是以1开始的,而C、C++默认的数组下标却是从0开始的,所以在调用时要注意加1或者减1,以保证调用到正确的数据。
Fortran语言里的结构经过声明后就被分配了空间,在C、C++里面也要声明它,采用下面的方式。
Fortran结构声明格式如下。
COMMON/COLOR7/C_RED,C_GREEN,C_BLUE
COMMON/NDDAT/NID(NASIZE),XN(3,NASIZE)
C、C++结构声明格式如下。
#ifdef_cplusplus
extern"C"{
#endif
#definecolor7COLOR7
#definenddatNDDAT
externstruct{floatc_red;floatc_green;floatc_blue;}color7;
externstruct{intnid[NASIZE];floatxn[NASIZE][3];}ndda;t
#ifdef_cplusplus
}
#endif
综合上述问题的研究,混合编程的优势在于它允许调用另一种语言编写的现有程序代码、使用在特定语言环境下难以实现的算法和获得处理速度方面的优势。在混合编程中的关键问题是协调2种或多种语言间所的调用约定、命名约定及参数传递方式,并使它们在数据结构、数据类型上保持一致。
参考文献
[1]张志华,王林江,吕庆风.混合编程与FORTRAN计算程序可视化[J].计算机应用,1999,19(6):33-35.
[2]袁平.多语言混合编程的技术关键及方法[J].电脑与信息技术,1996,(1):43-45.
[3]周振红.IntelVisualFortran应用程序开发[M].郑州:黄河水利出版社,2006.
[4]浩强工作组.Fortran经典程序设计[M].大连:大连理工大学出版社,2004.
作者简介:邹倩倩(1986—),女,青海西宁人,工学学士,助理工程师,现供职于辽宁省气象服务中心,研究方向:气象电子。