linux fortran 结构体,C与Fortran混合编程示例

今天单位GX姐给我们辅导了fortran和C语言的混编,培训内容如下,在此简单的介绍一下。

C与Fortran混合编程中,结构体在C语言和Fortran中都要定义一遍,并且内存和顺序都要一致,但名字可以不一样。

1.linux操作系统

RedHat Enterprise Linux Server release 6.6

2.编译器

C语言编译:gcc

Fortran语言编译:ifort

3.总体思路:

Fortran语言编写库函数,自己写一个makefile编译成可静态库

C语言编写可执行文件,自己写一个makefile编译成可执行文件,调用Fortran的静态库。

3.1Fortran库:

(1)Mod文件编译

Mod文件定义了Fortran与C公用的一些结构体,相当于C语言中的头文件。

使用下述命令可编译成*.mod文件,在makefile中引用即可

Ifort

-c -fPIC

-module

mod文件存放的绝对路径源文件存放的绝对路径

-o目标文件存放的绝对路径

注意:Fortran与C语言共用的结构体,定义时一定要保证变量的类型、大小、顺序一致性,因为调用库函数时是按照内存的顺序存放读取参数变量,而不是按照变量名读取的。

(2)源代码

以CO2反演模块为例:

包含四个源文件:tansat.f90

C语言调用的库函数的接口

tansat_io_def.f90变量类型的定义

tansat_io_input.f90库函数输入结构体的定义(L1b、T639)

tansat_io_output.f90库函数输出结构的定义(L2)

以上三个文件通过Ifort

-c -fPIC

-module生成mod文件,include到第一个f90文件中,将第一个文件编译成可执行程序。

tansat.f90

SubroutineTanSat(Input,Output)编译成库用Subroutine,可执行程序用program

fortune中!代表注释

!####################################################################

!TanSat XCO2 retrieval algorithm V2.0

!CO2 1.61, CO2 2.04 and O2A band

!Creat by Dongxu Yang (Dr.)

!Institude of Atmospheric Physics, Chinese Academy of

Science

!####################################################################

USE

tansat_Retrieval

mod文件

! Inclue the input/output type

defination

USE tansat_io_input

mod文件

USE

tansat_io_output

mod文件

IMPLICIT NONE强制标识符先定义后使,fortran里面有一项不好的功能,就是变量不经定义就可以使用,而且根据变量的开始字母自行给变量规定类型,加上implicitnone

后可以防止这个东西

TYPE(tansat_io_input_L1B_HSCO2_HDF)  ::

Input

TYPE(tansat_io_output_L2_HSCO2_HDF)  ::

Output

INTEGER(KIND=4)  ::

Input_fake !后面的类型是4个字节

INTEGER(KIND=4)  ::

Output_fake

CHARACTER(LEN=256)  ::

pathin

pathin = ''

pathin(1:Input%tansat_path%pathlen)

=Input%tansat_path%path(1:Input%tansat_path%pathlen)

print*,trim(pathin)//'data/log.tax'

!字符串连接,trim为fortune去掉空格

CALLtansat_Retrieval_ctl(Input_fake,Output_fake,pathin)调用子函数

END!结束代码的编写

注意:a.fortran对字符串的处理和c不一样,C语言字符串一般都以'\0'结束的,以数据0补足字符串的,所以len算出来的就是字符串实际的长度;而fortran是以空格补足字符串的,所以要用len_trim计算字符串实际的长度。所以当C语言将一个补零后的字符串传递给fortran时,fortran读到'\0'并不认为是结束,还会继续读取后面的0。所以需要告诉fortran

c语言中字符串的长度,把C语言的字符串逐个赋值给fortran,并用trim函数去掉fortran中的空格,才能进行字符串连接。

Fortran中连接字符串的函数是//。

tansat_io_input.f90

MODULE

tansat_io_input表明该文件是mod文件

USE

tansat_io_num_def,ONLY:INT_IO,DBP_IO,SRT_IO,FLT_IO,LNG_IO,USS_IO,UNS_IO

使用到的mod文件

IMPLICIT NONE

PUBLIC ::

tansat_io_input_L1B_HSCO2_META

PUBLIC

::tansat_io_input_L1B_HSCO2_DIMENSION

PUBLIC ::

tansat_io_input_L1B_HSCO2_HDF

。。。。。。。。

TYPE

tansat_io_input_L1B_HSCO2_DIMENSIONS

!定义变量

INTEGER(KIND=INT_IO)  :: AncFile

INTEGER(KIND=INT_IO)  :: Frame

END TYPE

tansat_io_input_L1B_HSCO2_DIMENSIONS

。。。。。。。。

ENDMODULE tansat_io_input

(3)makefile

编写Fortran程序,写makefile文件如下:

HOME= /usr/local

HOME1= /home/tansat/TanSat_V2.0T/debug

HOME2= /home/tansat/TanSat_V2.0T

FC=ifort

OUT_SRCS=

\源文件

../src/tansat.f90

OUT_OBJS=

\目标文件

./tansat.o

#OUT_SRCS=$(wildcard../src/*.f90)

#DIR=$(notdir$(SRCS))

#OUT_OBJS=$(patsubst%.f90,%.o,$(OUT_SRCS))

INCLUDE=

\包含的头文件路径

-I$(HOME)/hdf-5/include\

-I$(HOME)/netcdf-4/include\

-I$(HOME)/netcdf-fortran-4/include\

-I$(HOME2)/mod此处为包含的mod文件路径

ALLFLAG=

\包含的库,前面是路径,后面是库的名称

-L$(HOME)/hdf-5/lib-lhdf5 -lhdf5_fortran

-lhdf5_hl -lhdfhl_fortran \

-L$(HOME)/netcdf-4/lib-lnetcdf \

-L$(HOME)/netcdf-fortran-4/lib-lnetcdff \

-L/../lib/tansat_acc.so-L/../lib/tansat_fwd.so

-L/../lib/tansat_main.so

-L/../lib/tansat_lapack.so

!注意动态库和静态库的区别。动态库需要将所有路径都写上

all:libtansat.a

libtansat.a:$(OUT_OBJS)

ar -crv "libtansat.a"$(OUT_OBJS)

./%.o:../src/%.f90

$(FC) $(INCLUDE) -O0 -g -c-o"$@" "$

$(ALLFLAG)

.PHONY:clean

clean:

rm -f $(OUT_OBJS) libtansat.a

然后打开终端,运行下述命令:

makeclean

make

3.2

C语言可执行文件

必须强调的是,在C语言中调用Fortran库前,需要进行函数声明。

与C语言函数声明不同的是,Fortran函数后面需要加_,然后才可以在语言中调用。

(1)源文件

在*.cpp文件开始对Fortran函数进行声明:

#include

extern "C" void tansat_(

//注意下划线

L1B_HSCO2_HDF *l1b_hdf,

L2_HSCO2_HDF *l2_hdf

);

。。。。。。。

intProcessor::accelerate(CWriteLog

*log)

{

int i,ret;

printf("Start

Retrievalfunction!!!\n");

sounding_index = 5;

for(i=0;i

{

l1b_hdf.instrument_header

=RW->l1b_instrument_header[sounding_index];

l1b_hdf.sounding_measurements

=RW->l1b_sounding_measurements;

l1b_hdf.sounding_geometry

=RW->l1b_geometry;

for(int j= 0;j<256;j++)

{

l1b_hdf.datapath.strDataPath[j]= ' ';

}

strcpy(l1b_hdf.datapath.strDataPath,RW->strDataPath);

l1b_hdf.datapath.len

=strlen(l1b_hdf.datapath.strDataPath);

printf("l1b_hdf.strDataPath:%s\n",l1b_hdf.datapath.strDataPath);

printf("len:%d\n",l1b_hdf.datapath.len);

memcpy(l1b_hdf.t639.pres,RW->t639.pres,36*sizeof(float));

memcpy(l1b_hdf.t639.temp,RW->t639.temp,36*sizeof(float));

memcpy(l1b_hdf.t639.sh,RW->t639.sh,36*sizeof(float));

l1b_hdf.t639.pres0 =RW->t639.pres0;

l1b_hdf.t639.temp0 =RW->t639.temp0;

l1b_hdf.t639.sh0 =RW->t639.sh0;

tansat_(&l1b_hdf,&l2_hdf);

//注意下划线

RW->l2_HSCO2[i].Particles

=l2_hdf.Particles;

RW->l2_HSCO2[i].Surface =l2_hdf.Surface;

}

printf("endRetrievalfunction!!!\n");

return 0;

}

(2)makefile

CXXFLAGS=-O0-g -Wall -fmessage-length=0

CXX=g++

LIB+=  -lconfig -lTanhdf

-ltimestring -lhdf5 -lhdf5_fortran -lhdf5_hl

-lhdf5hl_fortran -ltansat -lnetcdf -lnetcdff包含的静态库

LIB+=/TANTDP/LIB/libCWriteLog_TAN.so包含的动态库

LIB+=/TANTDP/LIB/libParamDll_TAN.so包含的动态库

LIB+=../lib/tansat_acc.so包含的动态库

LIB+=../lib/tansat_main.so包含的动态库

LIB+=../lib/tansat_lapack.so包含的动态库

LIB+=../lib/tansat_fwd.so包含的动态库

LIB+=-I/home/T/src/include/头文件路径

LIB+=-I/usr/local/hdf-5/include/头文件路径

LIB+=-L/home/T/lib/静态库的路径

LIB+=-L/usr/local/hdf-5/lib/静态库的路径

LIB+=-L/usr/local/netcdf-4/lib/静态库的路径

LIB+=-L/usr/local/netcdf-fortran-4/lib/静态库的路径

SRCS=$(wildcard../src/*.cpp)

#DIR=$(notdir$(SRCS))

OBJS=$(patsubst%.cpp,%.o,$(SRCS))

EXEC=TANSAT

$(EXEC):$(OBJS)

$(CXX) -o $@ $^  $(LIB)

@echo "---------OK--------"

@echo "---------OK--------"

@echo "---------OK--------"

.cpp.o:

$(CXX) -o $@ -c $< $(CXXFLAGS)

clean:

rm -f $(OBJS)

然后打开终端,运行下述命令:

makeclean

make

4.运行可执行程序

./TANSAT../xml/input.xml ../xml/output.xml

以上工作中,forturan要做的工作:

fortran编译好三个mod,并将mod

include到主程序f90中,将主程序编译成.a文件。

C语言要做的工作:

首先将fortran定义的mod文件中结构体在C语言头文件中按顺序重新定义一下,在makefile中将fortran的库文件引用进来(通过so来引用a),然后在需要调用该库函数的cpp上将fortran定义的库函数extern声明一下,编译后就可以调用fortran函数了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值