我是一名C程序员,他必须通过添加对C函数的单个调用来更新庞大的Fortran 2003程序。
首先,我需要编写一个最小的Fortran包装器(在现代的,自由形式的Fortran中,没有喊叫),它将使用包含循环计数器的字符串正确调用C函数(如果可能的话,还有日期/时间) ,从一个循环中。
这应该是“简单的”,但我所做的搜索都没有为我创建足够的片段来创建一个有效的程序。
我在64位Linux下使用最近的64位版本的gfortran和Intel ifort编译器,测试代码需要使用两个编译器进行编译。
这是C定义,在send_to_port.c文件中:
int send_to_port(int port, char *data, unsigned int length);
添加了最后一个参数以允许Fortran不必担心尾随空值(我在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
帮助?
答案 0 :(得分:1)
除了M. S. B.关于参数计数的注释之外,接口块的语法已经完成,并且您需要将一些项引入接口体的范围。
请注意,*
作为write语句中的单位是OUTPUT_UNIT的同义词(更常见)(如果您想要最少的代码,PRINT语句也会写入该单元)。我还建议在str输出项周围使用TRIM()。类似地,LEN_TRIM(str)可能是一个合理的长度,作为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
答案 1 :(得分:0)
(是的,违反了fortran-iso-c-binding问号...)
如果你不能使iso-c绑定工作...根据编译器版本,我遇到了一些问题,我更喜欢在混合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)
由于没有接口语句,因此没有或参数大小/类型检查也没有转换