IVF与VS结合的Fortran IDE,由于VS中的项目只能使用同一种语言来编程,所以如果要实现C/C++调用Fortran的功能,目前只有将Fortran代码编译成动态库或静态库的方式来实现:
在介绍代码之前我觉得应该先介绍一下我们在实现C/C++调用Fortran功能时经常会遇到的一些问题和解决方法,因为很多人已经知道了怎样编写调用代码,但是遇到了一些问题,这样就可以直接看下面的解决方法,而不必看后面的一大堆代码了:
问题一:
在编译调用的C/C++程序时出现了一大堆的连接错误信息,如下:
1>LIBCMTD.lib(dbgheap.obj) : error LNK2005: __CrtSetCheckCount already defined in MSVCRTD.lib(MSVCR90D.dll)
1>LIBCMTD.lib(dbghook.obj) : error LNK2005: __crt_debugger_hook already defined in MSVCRTD.lib(MSVCR90D.dll)
1>LIBCMTD.lib(setlocal.obj) : error LNK2005: __configthreadlocale already defined in MSVCRTD.lib(MSVCR90D.dll)
1>LIBCMTD.lib(tidtable.obj) : error LNK2005: __encode_pointer already defined in MSVCRTD.lib(MSVCR90D.dll)
1>LIBCMTD.lib(tidtable.obj) : error LNK2005: __decode_pointer already defined in MSVCRTD.lib(MSVCR90D.dll)
以上错误都是函数重定义的错误,这是由于调用程序的“运行时库”类型和被调用程序的“运行时库”类型不一致造成的。解决方案是:
先看被调用的Fortran动态或静态库程序的形式库的类型,在“项目->属性->Fortran->Libraris-> Runtime Library",再看调用的C/C++程序的形式库的类型,在”项目->属性->Configuration Properties->C/C++->Code Generation->Runtime Library“;
如果Fortran是静态库并且配置Debug,则它的Runtime Library的类型一般是:
Debug Multithreaded (/libs:static /threads /dbglibs)
那么对应的C/C++程序Debug配置的Runtime Library的类型应该为:
Multi-threaded Debug (/MTd)
如果Fortran是静态库并且配置Release,则它的Runtime Library的类型一般是:
Multithreaded
那么对应的C/C++程序Release配置的Runtime Library的类型应该为:
Multi-threaded (/MT)
如果Fortran是动态库并且配置Debug,则它的Runtime Library的类型一般是:
Debug Multithread DLL (/libs:dll /threads /dbglibs)
那么对应的C/C++程序Debug配置的Runtime Library的类型应该为:
Multi-threaded Debug DLL (/MDd)
如果Fortran是动态库并且配置Release,则它的Runtime Library的类型一般是:
Multithread DLL (/libs:dll /threads)
那么对应的C/C++程序Release配置的Runtime Library的类型应该为:
Multi-threaded DLL (/MD)
问题二:
在调用Fortran静态库的时候,库的路径和名称都设置对了但是一直出现下面这样的连接错误:
error LNK2001: unresolved external symbol __imp__DataProcess
如果你的函数的定义像下面这样:
extern "C" int _declspec(dllimport) DataProcess()
那很好解决,只要将”_declspec(dllimport)“删除就可以了,因为调用静态库不需要这个声明,但是调用动态库时必须要有这个声明,如果去掉了还是有问题,那请再检查一遍静态库是否包含到项目中。
问题三:
在Fortran中调用C/C++传进来的回调函数时(运行时),出现下面的运行时错误:
Unhandled exception at 0x00000005 in FortranDllTest.exe: 0xC0000005: Access violation reading location 0x00000005.
那我们首先调试一下看是运行到哪一步出现这样的错误,在看看这一步的参数是否正确,起始一般是程序的堆栈被破坏导致的,很有可能是我们的回调函数的调用约定不正确造成的,这个调用约定只能是__cdecl,不能是__stdcall,否则就会出现上面的错误。
下面开始介绍程序了:
下面的例程都是将Fortran编译成动态库的方式:
1)简单的调用:
Fortran代码:
2)复杂调用:
Fortran代码:
callbackFunctioncallbackFunctioncallbackFunction
在Fortran中回调函数的声明可以像上面用Interface来声明也可以用下面这一句来代替:
logical,external :: Fun
但是这样就不能声明回调函数的参数类型了。
C/C++中回调函数的调用约定默认是__cdecl,如果不是请将它改为”__cdecl“这样才不会留下隐患。
如果要向Fortran中传递二维数组,特别要注意的是Fortran中是列先数组,而C/C++中是行先数组。