关于Fortran调用C++函数的小结
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
关于Fortran调用C++函数的小结
2017-3-12
背景
工作中遇到了需要在Fortran代码中调用C++提供的函数的情况。
通过在网上查阅资料,总结了实现方法,制作了一个实例。
工具
集成开发环境是VS2010。由于默认安装模式下的VS2010是无法编译调试Fortran的,所以又补充安装了Intel(R) Virual Fortran 2011(英特尔可视化Fortran编译器)。
参考资料分析
本文需要用到Fortran与C/C++的混合编程,Fortran和C/C++分别编译各自的功能模块源代码,得到各自的目标文件(.obj),然后集成链接这些obj 文件生成一个统一的可执行文件,实现对对方函数的调用,数据交换通过约定接口来实现[1]。
C++代码中函数说明前需要用到extern关键字,说明函数可以在本模块或其它模块中使用[2]。extern与"C"一起连用时,如: extern "C" void fun(int a, int b);则告诉编译器在编译fun这个函数名时按着C的规则去翻译相应的函数名而不是C++的,C++的规则在翻译这个函数名时会把fun这个名字变得面目全非[3]。
要在Fortran中调用C++的函数,意味着Fortran项目对C++项目产生了依赖关系,如果项目依赖项未设置会导致类似“无法解析的外部符号_XXX,该符号在函数_XX 中被引用”的错误。另外还要保证Fortran与C++项目的运行库设置都是“多线程调试”[4]。
实现过程
创建Fortran项目
1)启动VS2010,新建一个Fortran控制台应用程序,名称为Console1。
2)在该项目下的Source Files下添加一个新文件Source1.f90。
3)在Source1.f90中写入如下代码:
program main
implicit none
interface
subroutine SUB(a,b)
!DEC$ ATTRIBUTES C,ALIAS:'_sub'::SUB
!DEC$ ATTRIBUTES reference::a,b
integer a , b
end subroutine SUB
end interface
integer(4) a,b,c
a=100
b=1
write(*,*) "开始调用C++里的函数SUB"
call SUB(a,b)
read(*,*)
end program main
注:接口中为_sub这个来自于C++的函数起了个别名SUB,所以在后面调用SUB时其实就是调用_sub。
在接口中还规定了a和b两个参数的传递方式是传引用。
创建C++项目
在解决方案资源管理器中的“解决方案”处右键,添加一个新建项目,在新建窗口中选中Win32控制台应用程序,输入项目名称Cpp2。在随后弹出的应用程序设置中选择应用程序类型为静态库。
在项目的头文件中新建一个sub.h,在其中输入如下代码:
//sub.h
#ifndef _SUB_H
#define _SUB_H
extern"C"void_cdecl sub(int *a,int *b);
#endif
注:在头文件中使用#ifdef和#ifndef是非常重要的,可以防止双重定义的错误[5]。
在项目的源文件中新建一个sub.cpp,在其中输入如下代码:
//sub.cpp
#include"stdafx.h"
#include"sub.h"
#include
extern"C"void_cdecl sub(int *a,int *b)
{
std::cout<<"C++: 已经进入C++的函数内部\n"<<"a="<<*a<<",
b="<<*b< std::cout<<"a - b = "<<(*a - *b)< } 注:extern表示这个函数可以被外部使用;"C" 表示使用C的方式编译、生成,这样生成的函数名就会是_sub,而不是按C++默认的方式变成_sub@数字;_cdecl表示编译生成的obj文件中函数名为混合大小写格式,本例中的sub本来就全是小写,所以会变成_sub;另外注意:这里参数是指针,取值要用*a和*b。 设置Fortran项目的项目依赖项 在Console1项目上右键,选择项目依赖项,在弹出窗口中依赖项页内选中Cpp2,切换到生成顺序页,可以看到Cpp2排在Console1前面。 设置运行库 1)设置Fortran项目的运行库,在Console1项目上右键选择属性,然后找到【配置属性】 【Fortran】【Libraries】【Runtime Library】,设置其值为Debug Multithreaded(/libs:static/threads/dbglibs)即多线程调试。 2)设置C++项目的运行库,在Cpp2项目上右键选择属性,找到【配置属性】【C/C++】【代 码生成】【运行库】,设置其值为多线程调试(/MTd)。 生成项目 1)在解决方案上右键选择重新生成解决方案。 2)在解决方案所在的Console1文件夹下找到Debug文件夹,可以看到其中有一个Cpp2.lib 文件,这个静态库文件就是Cpp2项目生成的。 3)在Console1\Console1\Debug文件夹下可以看到Console1.exe文件,这个可执行文件是 Console1项目生成的。 注:如果要单独生成Cpp2,可以在Cpp2项目上右键选择重新生成。如果在Console1项目上右键选择重新生成,因为前文设置了项目依赖项的关系,Cpp2也会被生成。 启动调试 按下F5,启动调试。可以看到调试成功。