APP下载

Fortran与VB.NET的混合编程

2017-07-24胡文清詹杰民

关键词:字符串数组调用

胡文清,詹杰民

(中山大学工学院应用力学与工程系,广东 广州 510275)

Fortran与VB.NET的混合编程

胡文清,詹杰民

(中山大学工学院应用力学与工程系,广东 广州 510275)

Fortran语言具有很高的执行效率,广泛地应用于数值计算领域,积累了大量高效可靠的源程序,例如,Microsoft 公司的 IMSL Fortran程序库,为科学计算提供了强大的工具。VB.NET是完全面向对象的语言,与VB相比,VB.NET具有快速简易地开发功能更强大的Windows程序的优点。剖析了VB.NET通过动态链接库模式调用Fortran的混合编程,针对变量、字符串、数组、结构体、结构体数组等情况给出对应的调用方法,并给出了典型示例。为开发集合Fortran和VB.NET优点,兼具高执行效率和快速简易开发能力的软件提供技术支持。

Fortran;VB.NET;混合编程

Fortran编程语言于1954年由IBM工程师开发,是世界上最早出现的计算机高级程序设计语言,广泛应用于科学和工程计算领域。Fortran语法简明严谨,接近数学公式的自然描述,可以直接对矩阵和复数进行运算,在计算机里具有很高的执行效率。长久以来,Fortran积聚了一大批高效、可靠、经过考验的函数库、软件包等源程序。然而Fortran是面向过程的语言,在设计开发人机交互界面方面能力较弱,不利于图形处理,因此一般采用混合编程的形式,使用其他易于开发软件的编程语言开发软件界面,利用Fortran编写计算核心程序。

在Windows XP和更早的时代,程序员经常采用VB编程语言来进行软件开发。Visual Basic是一种由 Microsoft 公司开发的结构化的、模块化的、面向对象的、包含协助开发环境的事件驱动为机制的可视化程序设计语言。VB是世界上使用人数最多的开发语言之一。利用VB开发人机交互界面[1],计算核心程序用Fortran开发是普遍的选择[2],VB和Fortran的混合编程方法也已被广泛研究[3-4]。

随着科技的发展,现在的电脑平台普遍从XP时代的32位x86更换至WIN7时代的64位x64,XP时代的开发平台已不能满足需求。在windows XP时代,Visual Basic的版本还是VB6.0,Fortran的标准还是77、90、95的CVF,关于这些版本的混合编程的研究已有很多;在64位时代,VB已升级为VB.NET。2005年,微软宣布将不会再对非。NET版本的VB进行支持,因此将开发平台升级至VB.NET已是大势所趋。与VB相比,VB.NET是完全面向对象的语言,功能更加强大,开发者可以更快速的可视化开发网络应用程序、网络服务、Windows应用程序和服务器端组件。但是,由于VB.NET是基于.NET框架的,所开发的程序都被编译成微软中间语言(Microsoft Intermediate Language)的中间代码,然后通过.NET Framework的公共语言运行库(Common Language Runtime)来执行。在Visual Studio 2008以后的版本,Visual Basic.NET的特性已经与原来的大有不同。由于改动太大,VB.NET对VB的向后兼容并不好。另一方面,Fortran也从CVF变化为2003、2008标准的Intel Fortran。因此VB和Fortran的混合编程方法并不能直接使用在VB.NET上,如何实现VB.NET和Fortran的混合编程,是本文的研究重点。另外,本文除了对变量、字符串、数组等一般情况的混合编程方法进行了研究外,还对结构体、结构体数组等情况进行了研究,基本包括了VB.NET和Fortran混合编程中可能遇到的所有情况。

本文研究的开发平台为64位WIN7,Fortran为Intel(R) Visual Fortran Compiler Professional 11.1.038 +Microsoft Visual Studio 2008,VB.NET为Microsoft Visual Studio 2010。

1 混合编程的调用约定和实现方法

VB.NET和Fortran的调用方法通常有2种[5]:第1种是VB.NET实用Shell命令直接调用Fortran编译生成的exe文件,这种方法适合于计算量较大而交互操作不多的情况。但是这种方法VB.NET程序和Fortran程序是异步执行的,并不利于数据的实时交互;第2种方法是将Fortran程序编译成动态链接库(Dynamic Link Library),在VB.NET里通过约定的接口动态调用。这种方法又细分为隐式链接和显式链接,隐式链接需要将Fortran编译生成的LIB文件加载到VB.NET的工程中,即可直接调用Fortran的DLL。显式链接只需要Fortran编译生成的DLL文件,但是需要在VB.NET程序中显式声明需要调用的Fortran过程和函数。由于隐式链接方法在更新Fortran的DLL时需要每次都加载新的LIB文件,并不方便,因此一般采用显式链接方法来加载DLL。综上,本文采用VB.NET显式链接加载Fortran编译生成的DLL的方法来实现Fortran与VB.NET的混合编程。

不同的语言编写的程序之间的过程调用存在较大差异,因此在混合编程时必须保证调用约定的匹配。Fortran一共有3种调用约定:C、STDCALL、Default,VB.NET的默认调用约定为WinAPI,在32位Intel平台上对应于STDCALL。由于STDCALL调用约定用于调用Win32 API函数,也是VB.NET的默认调用约定,因此在Fortran处不采用默认调用约定,而是使用STDCALL,以符合Win32 API规范,这需要在Fortran源程序中声明[6-7]。

表1 STDCALL调用约定的实现Table 1 Calling convention of STDCALL

VB.NET通过.NET Framework的CLR来执行,称作托管代码,而VB的代码和Fortran编译的DLL属于非托管代码。因此VB.NET与Fortran的混合编程方法相对于VB时期有了相当的变化,这在本文后面部分再分别说明。

1.1 Fortran部分实现方法

Fortran编译DLL时,可以采用function或者subroutine形式。由于subroutine可以利用虚参实现多个返回值,因此一般采用subroutine形式。以下是示例代码段:

subroutine ftest(na,nb,a,b)

!DEC$ ATTRIBUTES STDCALL,DLLEXPORT::ftest

!DEC$ ATTRIBUTES ALIAS:"FTest"::ftest

!DEC$ ATTRIBUTES VALUE::na,nb

!DEC$ ATTRIBUTES REFERENCE::a,b

其中,!DEC$ ATTRIBUTES 语句用于定义该DLL工程的属性。STDCALL定义了该子过程使用STDCALL调用约定,DLLEXPORT表明该子过程能被外部其他程序或DLL调用。ALIAS属性定义了该子过程的别名,将编译产生的目标例程名限定为引号内的名称,以保持大、小写混合。使用ALIAS属性避免了在VB.NET的部分必须使用符合STDCALL调用约定的例程名称,而是能按程序员个人的意愿决定该子过程的例程名。VALUE和REFERENCE定义了该子过程的参数是按值传递还是按地址传递。STDCALL调用约定的默认参数传递约定是按值传递,而VALUE和REFERENCE属性的定义会覆盖调用约定对参数传递产生的影响,因此推荐将全部参数都显式定义其参数传递方式。

1.2 VB.NET部分实现方法

在VB.NET里,声明外部过程的语句如下:

Declare [Ansi|Unicode|Auto] Sub|Function 〈名称〉 Lib “〈库〉” [Alias “〈别名〉”] [([argumentList])]

对于1.1节定义的子过程,假设该DLL工程编译的DLL为ftest.dll,该DLL文件放在工程运行目录下,则VB.NET里使用Declare语句定义该过程,Call语句调用。以下是示例代码段:

Declare Ansi Sub FTest Lib "ftest.dll" (ByVal na As Integer, ByVal nb As Integer, ByRef a As Double, ByRef b As Long)

Call FTest(na, nb, a, b)

其中,Ansi用于指定VB.NET将所有的字符串封送为ANSI值。由于VB.NET的字符串使用Unicode编码,而Fortran的字符串使用ANSI编码,因此该处指定封送编码。Sub语句指定该外部过程为过程。FTest为过程的名称,与1.1节里ALIAS属性定义的别名一致。〈库〉指定引用DLL的路径,这里使用的是相对路径。Alias指定在VB.NET里的别名,并非必须。argumentList指定该过程的参数属性,ByVal为按值传递,ByRef为按地址传递。VB.NET的参数属性设置必须与Fortran的一致。

2 变量传递

VB.NET与Fortran的变量传递可以使用ByVal按值传递,也可以使用ByRef按地址传递。相比于VB,VB.NET对于Integer和Long的定义作了修改,因此程序员不能套用旧的VB定义。VB.NET与Fortran的常用数据类型对应关系如表2所示[8-9]。

表2 数据类型对应关系Table 2 Data types correspondence

以下是示例代码段:

Fortran

subroutine ftest(na,nb,a,b)

!DEC$ ATTRIBUTES STDCALL,DLLEXPORT::ftest

!DEC$ ATTRIBUTES ALIAS:"FTest"::ftest

!DEC$ ATTRIBUTES VALUE::na,nb

!DEC$ ATTRIBUTES REFERENCE::a,b

REAL(8)::a

INTEGER(8)::b

INTEGER(4):: na,nb

VB.NET

Declare Ansi Sub FTest Lib "ftest.dll" (ByVal na As Integer, ByVal nb As Integer, ByRef a As Double, ByRef b As Long)

Dim a As Double

Dim b As Long

Dim na, nb As Integer

Call FTest(na, nb, a, b)

3 字符串传递

Fortran的字符串传递时默认会在参数的最后附加一隐藏参数,该参数是字符串的长度,按值传递。通过设置调用约定和VALUE/REFERENCE属性可以改变传递方式。表3为详细情况[8]。

VB.NET的字符串类型实际是以包含长度和地址信息的结构体形式存储的。因此,VB.NET和Fortran的字符串传递必须以以下形式实现:

表3 Fortran传递字符串的ATTRIBUTE属性效果Table 3 Effect of ATTRIBUTE options on character strings passed as arguments in Fortran

VB.NET使用按值传递,Fortran使用按地址传递。VB.NET使用按值传递将间接引用存储字符串的结构体,实际上传递的只有字符串的地址,与Fortran所期望的一致。

在VB.NET里,字符串变量使用String定义,不能直接定义定长字符串,字符串长度在赋值后确定。同时,VB.NET字符串在最后会增加一个NULL字符作为结束标志,因此VB.NET字符串的总长度为字符数加一。混合编程时应先对VB.NET的字符串赋初值,使其长度与Fortran定长字符串一致。

Fortran里汉字的存储是两字节的ANSI码,因此VB.NET里需要声明Ansi属性。Fortran里统计字符串长度时一个汉字占用2个长度,但是在VB.NET里,统计字符串长度时一个汉字只占1个长度。这点程序员编写程序时应注意。

以下是示例代码段:

Fortran

subroutine ftest(chtt,chtt2)

!DEC$ ATTRIBUTES STDCALL,DLLEXPORT::ftest

!DEC$ ATTRIBUTES ALIAS:"FTest"::ftest

!DEC$ ATTRIBUTES REFERENCE::chtt,chtt2

character*5::chtt,chtt2

do i=1,len_trim(chtt)

chtt2(i:i)=chtt(len_trim(chtt)-i+1:len_trim(chtt)-i+1)

end do

VB.NET

Declare Ansi Sub FTest Lib "ftest.dll" (ByVal chtt As String, ByVal chtt2 As String)

Dim chtt, chtt2 As String

chtt = "a中cd"

chtt2 = "aaaaa"

Call FTest(chtt, chtt2)

该代码段的结果为chtt=”a中cd”,chtt2=”dc兄a”,观察汉字的GBK码(中D6D0,兄D0D6)可证上述结论。

4 数组传递

VB.NET和Fortran的数组传递只能使用按地址传递的方式。实际传递时VB.NET需要传递数组的第一个元素,按地址传递时这将传递给Fortran数组的开始地址,正如Fortran所需。

以下是示例代码段:

Fortran

subroutine ftest(c, ni, nj, nk, nl)

!DEC$ ATTRIBUTES STDCALL,DLLEXPORT::ftest

!DEC$ ATTRIBUTES ALIAS:"FTest"::ftest

!DEC$ ATTRIBUTES VALUE::ni, nj, nk, nl

!DEC$ ATTRIBUTES REFERENCE::c

integer(4)::ni, nj, nk, nl

real(4),dimension(1:ni,1:nj,1:nk,1:nl)::c

VB.NET

Declare Ansi Sub FTest Lib "ftest.dll" (ByRef c As Single, ByVal ni As Integer, ByVal nj As Integer, ByVal nk As Integer, ByVal nl As Integer)

Dim ni, nj, nk, nl As Integer: Dim c(,,,) As Single

ni = 5: nj = 4: nk = 3: nl = 2

ReDim c(0 To nl-1, 0 To nk-1, 0 To nj-1, 0 To ni-1)

Call FTest(c(0, 0, 0, 0), ni, nj, nk, nl)

可以见到VB.NET构造数组与Fortran有相当大的不同。以下两节将做出详细描述。

4.1 构造VB.NET数组

VB.NET的数组下标必须是0,不同于VB,VB可以使用option base语句来修改下标为0或1。尽管如此,VB.NET仍然可以构建下标不为0的数组。VB.NET采用CLR来执行,而CLR数组可以使用Array.CreateInstance方法来指定数组创建的维数和每维的起始索引值。示例如下:

Dim a(,,,), b(,,,) As Single

ReDim a(0 To nl-1, 0 To nk-1, 0 To nj-1, 0 To ni-1)

b = Array.CreateInstance(GetType(Single), {nl, nk, nj, ni}, {1, 1, 1, 1})

a和b数组均为类型相同的四维数组,每维的大小相等,区别只是起始索引值不同,a从0开始,b从1开始。Array.CreateInstance方法的第1个属性指定数组类型,第2个属性指定每维的大小,第3个属性指定每维的起始索引值。但是,这种方法不适用于一维数组。

Dim c(), d() As Single: ReDim c(0 To ni-1)

d = Array.CreateInstance(GetType(Single), {ni}, {1})

这里c和d并不是类型相同的数组,c的类型为single[],而d的类型为single[*]。这是因为CLR中有一种数组是被特殊照顾的,那就是以0开始的一维数组,这种数组也被称为“Vector”。Vector数组的类型为xxx[],Array.CreateInstance方法构造的一维数组类型为xxx[*]。因此,当使用一维数组混合编程时,VB.NET里只能以0开始,程序员需要注意和Fortran的不同;使用多维数组时,则可以使用Array.CreateInstance方法构造和Fortran数组起始索引值一致的数组。

4.2 VB.NET数组和Fortran数组的差异

习惯上,我们将数组前面的维度称为列,将后面的维度称为行。Fortran 数组存储时先改变前面的维度,因此,习惯称之为“列优先”存储。而VB.NET数组与之相反,为“行优先”存储。举例来说,VB.NET的数组 arr(4,3,2,1)与Fortran的arr(2,3,4,5)维度、大小均一致。

以下是示例代码段:

Fortran

subroutine ftest(c,d, ni, nj, nk, nl)

!DEC$ ATTRIBUTES STDCALL,DLLEXPORT::ftest

!DEC$ ATTRIBUTES ALIAS:"FTest"::ftest

!DEC$ ATTRIBUTES VALUE::ni, nj, nk, nl

!DEC$ ATTRIBUTES REFERENCE::c, d

integer(4)::ni, nj, nk, nl

real(4),dimension(1:ni,1:nj,1:nk,1:nl)::c,d

do l=1,nl

do k=1,nk

do j=1,nj

do i=1,ni

d(i,j,k,l)=c(i,j,k,l)+i+nj*(j-1)+nj*nk*(k-1)+nj*nk*nl*(l-1)

end do

end do

end do

end do

VB.NET

Declare Ansi Sub FTest Lib "ftest.dll" (ByRef c As Single, ByRef d As Single, ByVal ni As Integer, ByVal nj As Integer, ByVal nk As Integer, ByVal nl As Integer)

Dim ni, nj, nk, nl As Integer: Dim c(,,,), d(,,,) As Single

ni = 5: nj = 4: nk = 3: nl = 2

ReDim c(0 To nl-1, 0 To nk-1, 0 To nj-1, 0 To ni-1)

ReDim d(0 To nl-1, 0 To nk-1, 0 To nj-1, 0 To ni-1)

For l = 1 To nl

For k = 1 To nk

For j = 1 To nj

For i = 1 To ni

c(l-1,k-1, j-1,i-1)=i+nj*(j-1)+nj*nk*(k-1)+nj*nk*nl*(l-1)

Next

Next

Next

Next

Call FTest(c(0, 0, 0, 0), d(0, 0, 0, 0), ni, nj, nk, nl)

该代码段的VB.NET部分对c按照“行优先”赋值,Fortran部分对d按照“列优先”赋值,并且加上c的对应元素的值。结果d的每个元素的值均为c的对应元素的值的两倍, 证明了VB.NET数组与Fortran数组的差异。

5 结构体传递

结构体能够实现复杂的数据结构,在实际应用中经常使用到。因此VB.NET与Fortran混合编程的结构体传递问题是研究的重点。在VB.NET里使用Structure语句定义结构体,Fortran里使用type语句定义。VB.NET里结构体的定义方法与VB相比有了很大的变化。VB.NET与Fortran使用结构体传递需要注意以下2个问题:① VB.NET属于托管代码,定义的结构体中的数组成员不能声明初始大小,需要在结构体里构造初始化函数重定义数组大小;② 无论是VB.NET还是Fortran,结构体中的成员在存储结构上是自然对齐的,未必按照声明次序来存储。

为解决这2个问题,需要在VB.NET里引入System.Runtime.InteropServices命名空间。利用此命名空间的MarshalAs属性,可以指定如何在托管内存与非托管内存之间封送数据,从而解决问题。

以下是示例代码段:

Fortran

subroutine ftest(tt)

!DEC$ ATTRIBUTES STDCALL,DLLEXPORT::ftest

!DEC$ ATTRIBUTES ALIAS:"FTest"::ftest

!DEC$ ATTRIBUTES REFERENCE::tt

type test

sequence

real(8)::cc

integer(8)::iii

real(4),dimension(0:3)::ccc

character*12::str

integer(4)::abc

integer(4)::cba

end type

type(test)::tt

VB.NET

Imports System.Runtime.InteropServices

Declare Ansi Sub FTest Lib "ftest.dll" (ByRef tt As test)

Public Structure test

Dim cc As Double: Dim iii As Long

Dim ccc() As Single

Dim str As String

Dim abc As Integer: Dim cba As Integer

Public Sub int()

ReDim ccc(0 To 3)

End Sub

End Structure

Dim tt As test: tt.int(): Call FTest(tt)

如以上代码段所示,为避免问题2,必须在VB.NET和Fortran都声明为顺序存储。Fortran的实现方法是在结构体定义里加入SEQUENCE属性,VB.NET则是使用StructLayout属性定义。LayoutKind.Sequential规定了结构体成员按声明顺序存储。CharSet属性设置结构体采用ANSI编码,原因见第3部分。由于Fortran的默认对齐长度为4字节,因此VB.NET需要使用pack属性设置结构体存储时按4字节对齐。

由于VB.NET字符串不能声明初始长度,结构体里数组也不能声明初始大小,因此需要采用MarshalAs属性指明封送数据的大小。其中UnmanagedType.ByValArray作用于数组,UnmanagedType.ByValTStr作用于字符串,SizeConst属性指定大小。为实际分配空间,需要在结构体里构造初始化函数int(),先初始化后再Call调用。

利用MarshalAs属性可以为结构体的数组成员指明大小,但是这种方法只适用于一维数组。为了构造VB.NET结构体的多维数组成员,可行的方法是将多维数组拆分为多个一维数组,这样就可以为每个维度数组设置MarshalAs属性。

以下是示例代码段:

Fortran

subroutine ftest(tt)

!DEC$ ATTRIBUTES STDCALL,DLLEXPORT::ftest

!DEC$ ATTRIBUTES ALIAS:"FTest"::ftest

!DEC$ ATTRIBUTES REFERENCE::tt

type test

sequence

real(4),dimension(1:6,1:2)::ddd

end type

type(test)::tt

VB.NET

Imports System.Runtime.InteropServices

Declare Ansi Sub FTest Lib "ftest.dll" (ByRef tt As test)

Public Structure test

Dim ddd() As structest

Public Sub int()

ReDim ddd(0 To 1)

For i = 0 To 1

ReDim ddd(i).ddda(0 To 5)

Next

End Sub

End Structure

Public Structure structest

Dim ddda() As Single

End Structure

Dim tt As test: tt.int():Call FTest(tt)

如以上代码段所示,将二维数组拆分为2个一维数组,则可分别为每个维度设置MarshalAs属性指明大小。需要注意的是,多维数组拆分时仍需注意第4部分所述的Fortran与VB.NET的存储顺序差异,保证Fortran遵照“列优先”存储,VB.NET遵照“行优先”存储。

6 结构体数组传递

VB.NET与Fortran的结构体数组传递不能使用第4部分数组传递的方法,使用普通数组传递的方法时结构体数组只能传递第一个数组元素。这是因为VB.NET属于托管代码,是CLR自动分配内存地址和垃圾回收的。而Fortran属于非托管代码,VB.NET与Fortran进行结构体数组传递时,托管对象可能已经被垃圾回收器回收了,就会出问题。这里就需要使用System.Runtime.InteropServices命名空间的GCHandle类,该类提供用于从非托管内存访问托管对象的方法,利用其Alloc方法将托管对象设置为Pinned类型,固定对象的内存地址,从而防止垃圾回收器移动对象回收掉。最后结束时使用Free方法释放已分配的句柄。

以下是示例代码段:

Fortran

subroutine ftest(ta,na,nb)

!DEC$ ATTRIBUTES STDCALL,DLLEXPORT::ftest

!DEC$ ATTRIBUTES ALIAS:"FTest"::ftest

!DEC$ ATTRIBUTES REFERENCE::tt

type test

sequence

real(8)::cc

integer(8)::iii

real(4),dimension(0:3)::ccc

character*12::str

real(4),dimension(1:6,1:2)::ddd

integer(4)::abc

integer(4)::cba

end type

type(test),dimension(1:na,1:nb)::ta

integer(4 ):: na,nb

VB.NET

Imports System.Runtime.InteropServices

Declare Ansi Sub FTest Lib "ftest.dll" (ByVal pt As IntPtr, ByVal na As Integer, ByVal nb As Integer)

Public Structure test

Dim cc As Double: Dim iii As Long

Dim ccc() As Single

Dim str As String

Dim ddd() As structest

Dim abc As Integer: Dim cba As Integer

Public Sub int()

ReDim ccc(0 To 3): ReDim ddd(0 To 1)

For i = 0 To 1

ReDim ddd(i).ddda(0 To 5)

Next

End Sub

End Structure

Public Structure structest

Dim ddda() As Single

End Structure

Dim na, nb As Integer: Dim ta(,) As test

Dim ipt As IntPtr: Dim pt As IntPtr: ReDim ta(0 To nb-1, 0 To na-1)

For l = 0 To nb -1

For k = 0 To na-1

ta(l, k).int()

Next

Next

Dim tryon() As Byte: Dim gc As GCHandle

ReDim tryon(Marshal.SizeOf(GetType(test))*na*nb-1)

gc = GCHandle.Alloc(tryon, GCHandleType.Pinned): pt = gc.AddrOfPinnedObject

For j = 0 To nb-1

For i = 0 To na-1

ipt = pt.ToInt32 + Marshal.SizeOf(GetType(test)) * i + Marshal.SizeOf(GetType(test)) * j * na

Marshal.StructureToPtr(ta(j, i), ipt, True)

Next

Next

Call FTest(pt, na, nb)

For j = 0 To nb-1

For i = 0 To na-1

ipt = pt.ToInt32 + Marshal.SizeOf(GetType(test)) * i + Marshal.SizeOf(GetType(test)) * j * na

ta(j, i) = Marshal.PtrToStructure(ipt, GetType(test))

Next

Next

gc.Free()

如以上代码段所示,VB.NET和Fortran进行结构体数组传递时需要注意以下3点:

1) 使用GCHandle类来传递结构体数组时,需要使用Byte数组来作数据存储。这是因为来用于固定数组的GCHandle的Alloc方法不能以结构体作为参数,因此需要利用Byte数组作媒介。使用时需要将该Byte数组的大小重定义与结构体数组的大小严格一致。单个结构体的大小使用Marshal类的SizeOf语句获得。

2)使用IntPtr类型作为该Byte数组的指针来作为函数参数传递,这点与单一结构体传递时直接将结构体作为函数参数不同。IntPtr用于表示指针或句柄的平台特定类型,使用GCHandle的AddrOfPinnedObject属性将IntPtr变量指向该Byte数组的内存首地址。利用Marshal的StructureToPtr方法通过IntPtr变量给Byte数组赋值,同样调用后需要用Marshal的PtrToStructure方法通过IntPtr变量将Byte数组的值传递回目标结构体数组中。

3)无论是给Byte数组赋值时还是将Byte数组的值传递回目标结构体数组,均需要使用循环结构对目标结构体数组的每一个成员进行操作。这里仍然需要注意本文第4部分所述的Fortran与VB.NET的存储顺序差异,保证Fortran遵照“列优先”存储,VB.NET遵照“行优先”存储。

7 总 结

本文详细介绍了Fortran与VB.NET在64位Windows平台上混合编程的方法,并给出了相应的示例。通过对变量、字符串、数组、结构体、结构体数组等情况的混合编程方法的研究,基本解决了在Fortran和VB.NET混合编程中可能出现的各种问题,从而为在64位平台上,以DLL为纽带充分发挥Fortran强大的计算能力和VB.NET的可视化程序开发提供了坚实的技术基础。

[1] 陈晓翔,柯栋,李芳,等. 非标准格式地理空间数据的GIS方式直接读取研究[J]. 中山大学学报(自然科学版), 2002, 41(2): 117-118. CHEN X X, KE D, LI F, et al. A study of GIS-based direct reading of nonstandard geographic spatial data [J]. Acta Scientiarum Naturalium Universitatis Sunyatseni, 2002, 41(2): 117-118.

[2] 刘祚秋,温少荣,周翠英,等. 桩、土、刚性承台相互作用下桩基内力计算新方法[J]. 中山大学学报(自然科学版), 2004, 43(4): 33-37. LIU Z Q, WEN S R, ZHOU C Y, et al. The new computing method of internal force of piles under the Interaction of piles, soils and rigid cap [J]. Acta Scientiarum Naturalium Universitatis Sunyatseni, 2004, 43(4): 33-37.

[3] 欧阳永忠,王瑞,陆秀平,等. VC、VB与FORTRAN的混合编程技术及其实现[J]. 海洋测绘, 2004, 24(1): 54-59. OUYANG Y Z, WANG R, LU X P, et al. On mixed-language programming and realization with VC, VB and Fortran [J]. Hydrographic Surveying and Charting, 2004, 24(1): 54-59.

[4] 李学哲, 白云, 陈国新. Fortran 90与VB混合编程技术的研究与实现[J]. 苏州科技学院学报(工程技术版), 2008, 21(4): 76-80. LI X Z, BAI Y CHEN G X. The research and implementation of VB and Fortran90 mixed-language programming technology [J]. J of University of Science and Technology of Suzhou (Engineering and Technology), 2008, 21(4): 76-80.

[5] 何萌, 柴军瑞. VB与FORTRAN混合编程的两种方法及其比较[J]. 水电能源科学, 2005(1): 60-62. HE M, CHAI J R. Two kinds of methods of mixing VB and Fortran in one program and their comparison [J]. Water Resources and Power, 2005(1): 60-62.

[6] 毕苏萍, 周振红. Visual Fortran创建Win32 API式的DLL[J]. 计算机工程与设计, 2008, 29(18): 4868-4871. BI S P, ZHOU Z H. Creating DLL in accordance with win32 API in visual Fortran [J]. Computer Engineering and Design, 2008, 29(18): 4868-4871.

[7] 颜国红, 周振红. 工程计算平台CVF的应用接口资源扩充[J]. 长江科学院院报, 2008, 25(4): 106-110. YAN G H, ZHOU Z H. How to extend API in engineering computation platform of CVF [J]. Journal of Yangtze River Scientific Research Institute, 2008, 25(4): 106-110.

[8] INTEL CORP. Intel Fortran compiler 11.1 user and reference guides [M]. USA: Intel Corporation, 2009.

[9] MICROSOFT CORP. Microsoft visual studio 2010 documentation [M]. USA: Microsoft Corporation, 2010.

Mixed-language programming with Fortran and VB.NET

HU Wenqing, ZHAN Jiemin

(Department of Applied Mechanics and Engineering, College of Engineering, Sun Yat-sen University, Guangzhou 510275, China)

Fortran language has high execution efficiency. It is widely used in the field of numerical calculation. And it has accumulated a lot of high-efficient and reliable source codes. For example, The Microsoft IMSL-Fortran Library can give powerful mathematical and statistical analysis. VB.NET is a fully object-oriented language. Compared against VB language, VB.NET is quicker and easier to develop a more powerful Windows program. Mixed-language programming of VB.NET calling Fortran through dynamic link library mode is studied. It gives the corresponding calling method for variable, string, array, structure and structure array. Also the typical examples are offered. It provides technical support for the development of software with both advantages of Fortran and VB.NET: high execution efficiency and quick and easy development ability.

Fortran; VB.NET; mixed-language programming

10.13471/j.cnki.acta.snus.2017.04.001

2016-07-25 基金项目:广东省协同创新与平台环境建设专项(2014B090904066)

胡文清(1987年生),男;研究方向:流体力学;E-mail: emp_beren@163.com

詹杰民(1963年生),男;研究方向:流体力学;E-mail: stszjm@mail.sysu.edu.cn

TP311

A

0529-6579(2017)04-0001-08

猜你喜欢

字符串数组调用
JAVA稀疏矩阵算法
基于文本挖掘的语词典研究
JAVA玩转数学之二维数组排序
核电项目物项调用管理的应用研究
系统虚拟化环境下客户机系统调用信息捕获与分析①
更高效用好 Excel的数组公式
SQL server 2008中的常见的字符串处理函数
倍增法之后缀数组解决重复子串的问题
最简单的排序算法(续)
寻找勾股数组的历程