繁体   English   中英

从fortran调用C(ifort,gfortran)

[英]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。

您的代码包含对fdatesleep的引用,这不是标准内在函数。 请注意,这些行为在您的编译器之间可能有所不同(我认为您还可以,但是您应该检查一下。其中的第一个可能可以由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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM