VC 2005 如何调用fortran 库函数
答案:2 悬赏:20 手机版
解决时间 2021-11-24 14:57
- 提问者网友:你给我的爱
- 2021-11-23 17:02
VC 2005 如何调用fortran 库函数
最佳答案
- 五星知识达人网友:煞尾
- 2021-11-23 17:56
正好最近一个项目需要在C/C++程序中调用Fortran写的DLL, 有一些心得记录下来.
我用的C/C++集成环境是VC8(.Net 2005), Fortran编译用了Intel Visual Fortran Compiler 9.1, 在WindowsXP SP2上进行开发.
调试的时候, Dependency Walker这个软件很有用, 能直接看到编译出来的DLL中的信息.
首先写了一个fortranlib.dll, 很简单, 只有一个函数, 代码如下:
double precision function testfunc(x, y)
!DEC$ ATTRIBUTES DLLEXPORT, STDCALL::testfunc
!DEC$ ATTRIBUTES VALUE::x, y
implicit none
double precision x, y
testfunc = x - y
return
end function testfunc
然后写了一个callfortran.exe, 代码如下:
#include
extern "C" double __stdcall testfunc(double x, double y);
int main(int argc, char* argv[])
{
double a = 2.0;
double b = 1.0;
double c;
c = testfunc(a, b);
std::cout << b << std::endl;
return 0;
}
需要将fortranlib.lib作为callfortran.exe的additional dependency才能编译通过, 然后就可以work了.
如果两边都采用C的calling convention, 也可以编译通过且正确运行. 修改如下:
testfunc函数代码:
double precision function testfunc(x, y)
!DEC$ ATTRIBUTES DLLEXPORT, C::testfunc
!DEC$ ATTRIBUTES VALUE::x, y
implicit none
double precision x, y
testfunc = x - y
return
end function testfunc
并且callfortran.exe中函数引入声明改为:
extern "C" double __cdecl testfunc(double x, double y);
另外, 如果要采用REFERENCE型的传参规则, 以stdcall为例, 应改为:
testfunc函数代码:
double precision function testfunc(x, y)
!DEC$ ATTRIBUTES DLLEXPORT, STDCALL::testfunc
!DEC$ ATTRIBUTES REFERENCE::x, y
implicit none
double precision x, y
testfunc = x - y
return
end function testfunc
并且callfortran.exe中函数引入声明改为:
extern "C" double __stdcall testfunc(double* x, double* y);
要注意的几点:
1. Fortran忽略大小写, 如果代码中函数名含大写, 那么在编译出来的库中, 函数名称全部都被转成小写了(用Dependency Walker可以看到). 而C/C++是区分大小写的, 所以在C/C++中声明extern的函数时必须用小写的名字, 除非fortran函数被"!DEC$ ATTRIBUTE ALIAS"指令强制化名为含大写字母的名称.
2. Fortran中的几个涉及到Calling Convention和传参规则的"!DEC$"指令, 最好都显式的写出来. 因为不同的编译器以及在不同的操作系统上, 默认的编译行为都很可能不一样. 采用默认行为容易遇到一些原因很难查清的问题. C/C++也一样, 最好显式的写清楚是__cdecl还是__stdcall.
我用的C/C++集成环境是VC8(.Net 2005), Fortran编译用了Intel Visual Fortran Compiler 9.1, 在WindowsXP SP2上进行开发.
调试的时候, Dependency Walker这个软件很有用, 能直接看到编译出来的DLL中的信息.
首先写了一个fortranlib.dll, 很简单, 只有一个函数, 代码如下:
double precision function testfunc(x, y)
!DEC$ ATTRIBUTES DLLEXPORT, STDCALL::testfunc
!DEC$ ATTRIBUTES VALUE::x, y
implicit none
double precision x, y
testfunc = x - y
return
end function testfunc
然后写了一个callfortran.exe, 代码如下:
#include
extern "C" double __stdcall testfunc(double x, double y);
int main(int argc, char* argv[])
{
double a = 2.0;
double b = 1.0;
double c;
c = testfunc(a, b);
std::cout << b << std::endl;
return 0;
}
需要将fortranlib.lib作为callfortran.exe的additional dependency才能编译通过, 然后就可以work了.
如果两边都采用C的calling convention, 也可以编译通过且正确运行. 修改如下:
testfunc函数代码:
double precision function testfunc(x, y)
!DEC$ ATTRIBUTES DLLEXPORT, C::testfunc
!DEC$ ATTRIBUTES VALUE::x, y
implicit none
double precision x, y
testfunc = x - y
return
end function testfunc
并且callfortran.exe中函数引入声明改为:
extern "C" double __cdecl testfunc(double x, double y);
另外, 如果要采用REFERENCE型的传参规则, 以stdcall为例, 应改为:
testfunc函数代码:
double precision function testfunc(x, y)
!DEC$ ATTRIBUTES DLLEXPORT, STDCALL::testfunc
!DEC$ ATTRIBUTES REFERENCE::x, y
implicit none
double precision x, y
testfunc = x - y
return
end function testfunc
并且callfortran.exe中函数引入声明改为:
extern "C" double __stdcall testfunc(double* x, double* y);
要注意的几点:
1. Fortran忽略大小写, 如果代码中函数名含大写, 那么在编译出来的库中, 函数名称全部都被转成小写了(用Dependency Walker可以看到). 而C/C++是区分大小写的, 所以在C/C++中声明extern的函数时必须用小写的名字, 除非fortran函数被"!DEC$ ATTRIBUTE ALIAS"指令强制化名为含大写字母的名称.
2. Fortran中的几个涉及到Calling Convention和传参规则的"!DEC$"指令, 最好都显式的写出来. 因为不同的编译器以及在不同的操作系统上, 默认的编译行为都很可能不一样. 采用默认行为容易遇到一些原因很难查清的问题. C/C++也一样, 最好显式的写清楚是__cdecl还是__stdcall.
全部回答
- 1楼网友:一叶十三刺
- 2021-11-23 18:19
VC 2005和Fortran混合编程借助于Fortran生成的DLL进行(采用C默认的传址方式进行函数参数传递)方法和实例:
1.Fortran
生成DLL
新建Fortran
DLL程序test1.f
添加如下代码:
! test1.f90
!
! FUNCTIONS/SUBROUTINES
exported from test1.dll:
! test1 -
subroutine
!示例没有返回值的子例程
subroutine
test1(a,b)
! Expose subroutine test1 to
users of this DLL
!
!DEC$ ATTRIBUTES
C,DLLEXPORT::test1
! Variables
! Body of
test1
integer a,b
integer sum
sum=a+b
return
end subroutine
test1
!示例有返回值的整数四则运算
!两数相加
function
add(a,b)
implicit none
!DEC$ ATTRIBUTES
C,DLLEXPORT::add
integer
a,b,add
add=a+b
return
end
!两数相减
function
abstract(a,b)
implicit none
!DEC$ ATTRIBUTES
C,DLLEXPORT::abstract
integer
a,b,abstract
abstract=a-b
return
end
!两数相乘
function
multiply(a,b)
implicit none
!DEC$ ATTRIBUTES
C,DLLEXPORT::multiply
integer
a,b,multiply
multiply=a*b
return
end
!两数相除
(需要添加考虑被除数是否为0以及能否整除的判断)
function
divided(a,b)
implicit none
!DEC$ ATTRIBUTES
C,DLLEXPORT::divided
integer
a,b,divided
divided=a/b
return
end
编译后生成test1.dll,test1.obj等文件。其中这两个文件是我们在VC中调用所需要的。
1.Fortran
生成DLL
新建Fortran
DLL程序test1.f
添加如下代码:
! test1.f90
!
! FUNCTIONS/SUBROUTINES
exported from test1.dll:
! test1 -
subroutine
!示例没有返回值的子例程
subroutine
test1(a,b)
! Expose subroutine test1 to
users of this DLL
!
!DEC$ ATTRIBUTES
C,DLLEXPORT::test1
! Variables
! Body of
test1
integer a,b
integer sum
sum=a+b
return
end subroutine
test1
!示例有返回值的整数四则运算
!两数相加
function
add(a,b)
implicit none
!DEC$ ATTRIBUTES
C,DLLEXPORT::add
integer
a,b,add
add=a+b
return
end
!两数相减
function
abstract(a,b)
implicit none
!DEC$ ATTRIBUTES
C,DLLEXPORT::abstract
integer
a,b,abstract
abstract=a-b
return
end
!两数相乘
function
multiply(a,b)
implicit none
!DEC$ ATTRIBUTES
C,DLLEXPORT::multiply
integer
a,b,multiply
multiply=a*b
return
end
!两数相除
(需要添加考虑被除数是否为0以及能否整除的判断)
function
divided(a,b)
implicit none
!DEC$ ATTRIBUTES
C,DLLEXPORT::divided
integer
a,b,divided
divided=a/b
return
end
编译后生成test1.dll,test1.obj等文件。其中这两个文件是我们在VC中调用所需要的。
我要举报
如以上问答信息为低俗、色情、不良、暴力、侵权、涉及违法等信息,可以点下面链接进行举报!
大家都在看
推荐资讯