[英]Calling C from fortran (ifort, gfortran)
我是一名C程序员,必须通过向C函数添加单个调用来更新庞大的Fortran 2003程序。
首先,我需要编写一个最小的Fortran包装器(在现代的自由格式Fortran中,不要大喊大叫),它将从内部正确地使用包含循环计数器(以及日期/时间)的字符串调用C函数。一个循环。
这应该是“容易的”,但是我所做的任何搜索都没有为我创建足以创建工作程序的片段。
我正在使用最新的64位版本的gfortran和64位Linux下的Intel ifort编译器,并且测试代码需要使用这两种编译器进行编译。
这是C定义,位于文件send_to_port.c中:
int send_to_port(int port, char *data, unsigned int length);
添加了最后一个参数,以使Fortran不必担心结尾的null(我在C中处理它:data [length] ='\\ 0';)。 我了解到长度参数是由Fortran“自动”添加的,因此Fortran调用将只有两个参数,即整数端口号和要发送的字符串。
我希望使用以下gfortran行以及等效的ifort来编译代码:
gfortran -ffree-form test.f -o test send_to_port.o
我正在寻找最少的代码:我认为应该在10到20行左右,但是我不知道Fortran。 这是我当前用于test.f的编辑缓冲区(不会编译):
use iso_c_binding
use iso_fortran_env, stdout => output_unit
implicit none
! Fortran interface to C routine:
! int send_to_port(int port, char *data, unsigned int length);
interface
integter(c_int) function send_to_port(port, data) bind(C)
integer(c_int), value :: port
character(kind=c_char) :: data(*)
end interface
integer(c_int) retval, cnt, port
character(1024) str
cnt = 0
port = 5900
do ! Infinite loop (^C to exit)
call fdate(date)
cnt = cnt + 1
write(str, "(A,A,I8)") date, ": Iteration = ", cnt
write(stdout, *) str ! Show what's about to be sent
retval = send_to_port(port, str) ! Send it
write(stdout, *) retval ! Show result
call sleep(1)
end do
end
救命?
除了MSB关于参数计数的注释外,接口块的语法已用完,还需要将一些项目引入接口主体的范围。
请注意, *
作为write语句中的单元是OUTPUT_UNIT的同义词(并且更为典型)(并且PRINT语句也写入该单元-如果您需要最少的代码)。 我还建议在str输出项周围使用TRIM()。 同样,LEN_TRIM(str)可能是合理的长度,可以作为send_to_port
的第三个参数send_to_port
。
不要将.f用作自由格式Fortran源代码的扩展名,而应使用.f90。
您的代码包含对fdate
和sleep
的引用,这不是标准内在函数。 请注意,这些行为在您的编译器之间可能有所不同(我认为您还可以,但是您应该检查一下。其中的第一个可能可以由DATE_AND_TIME内在函数以及一些适当的文本格式代码替换,以提供一种更可移植的解决方案。
use, intrinsic :: iso_c_binding, only: c_int, c_char
implicit none
interface
function send_to_port(port, data, length) bind(C)
use, intrinsic :: iso_c_binding, only: c_int, c_char
implicit none
integer(c_int), value :: port
character(kind=c_char) :: data(*)
integer(c_int), value :: length
integer(c_int) :: send_to_port
end function send_to_port
end interface
integer(c_int) :: retval, port
integer :: cnt
character(len=1024,kind=c_char) :: str
character(30) :: date
cnt = 0
port = 5900_c_int
do ! Infinite loop (^C to exit)
call fdate(date)
cnt = cnt + 1
write(str, "(A,A,I8)") trim(date), ": Iteration = ", cnt
print *, trim(str) ! Show what's about to be sent
retval = send_to_port(port, str, len_trim(str)) ! Send it
print *, retval ! Show result
call sleep(1)
end do
end
(是的,违背了fortran-iso-c-binding问号...)
如果您不能使iso-c-binding正常工作...根据编译器版本的不同,我会遇到一些问题,并且我更喜欢在混合C和FORTRAN时花点时间:避免接口只需为C创建一个“包装器”功能。
包装指南大致如下:
函数名称必须以_结尾(在Linux上。在Windows上,函数名称必须为ALL_CAPS,且不带尾随_)
如果在C ++程序中编译,则定义为extern“ C”
所有参数都是指针
在内存中,多维数组索引被颠倒[i] [j]为[j] [i]
因此,C代码为:
extern "C"
void send_to_port_fort_(int* port, char *data, int* length, int *result)
{
*result = send_to_port(*port,data,*length);
}
然后从fortran
call send_to_port_fort(port,data,size(data),retval)
由于没有接口语句,因此没有或参数大小/类型检查或转换
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.