将标量和数组(任何尺寸)从Fortran传递到C [英] Passing both scalars and arrays (of any dimensions) from Fortran to C
问题描述
我有以下名为 show_value
的Fortran子例程,该子例程调用名为 show_value
的C函数:
I have the following Fortran subroutine named show_value
that calls a C function named show_value
:
INTERFACE
SUBROUTINE show_value(variable) BIND(C, name = "show_value")
USE, INTRINSIC :: iso_c_binding
TYPE(*) :: variable
END SUBROUTINE
END INTERFACE
C函数 show_value
:
void show_value(const void *variable)
{
printf("%d\n", *(int *) variable);
}
在将标量传递给它时,Fortran子例程运行良好.示例:
The Fortran subroutine works well when passing scalars to it. Example:
INTEGER :: x
x = 12
call show_value(x)
这将调用C函数 show_value
并打印 12
,这是正确的.
This will call the C function show_value
and print 12
, which is correct.
现在,根据Fortran文档,如果要启用子例程 show_value
来接收(任意尺寸的)数组,而不仅仅是标量,则可以输入 TYPE(*)::变量
应更改为 TYPE(*),DIMENSION(..)::变量
.
Now, according to the Fortran documentation, if one wants to enable subroutine show_value
to receive also arrays (of any dimensions) and not just scalars, the line TYPE(*) :: variable
should be changed to TYPE(*), DIMENSION(..) :: variable
.
进行此更改后,在执行以下Fortran代码时:
After making this change, when executing the following Fortran code:
INTEGER, DIMENSION(3) :: y
y(1) = 15
y(2) = 17
y(3) = 19
call show_value(y)
C函数 show_value
不再打印正确的消息(即打印随机数).此外,我发现C函数收到的地址比原始地址(在Fortran中)低528.要确认这一点:
The C function show_value
no longer prints the correct message (i.e. prints random numbers). Moreover, I found out that the address that the C function receives is 528 lower than the original (in Fortran). To confirm this:
void show_value(const void *variable)
{
printf("%d\n", *(int *) (variable + 528));
}
...打印 15
(正确的数字).
... which prints 15
(correct number).
有什么想法吗?
环境:Ubuntu 14.04 64位,gfortran 4.9
Environment: Ubuntu 14.04 64 bit, gfortran 4.9
推荐答案
尽管您的第一种情况是标量参数,但在假定调用参数为实参的情况下,它与 void *
参数正确匹配-rank(由 type(*),Dimension(..)::变量
表示)Fortran过程不能与具有相应形式参数 const void * variable
.
Although your first case, with scalar argument, works correctly matching with the void*
argument, when the argument to the call is assumed-rank (which type(*), dimension(..) :: variable
represents) the Fortran procedure is not interoperable with the C procedure with corresponding formal argument const void *variable
.
相反,有必要使用 CFI_cdesc_t
机制:
Instead, it is necessary to use the CFI_cdesc_t
mechanism:
#include <stdio.h>
#include <ISO_Fortran_binding.h>
void show_value(const CFI_cdesc_t* variable)
{
printf("%d\n", *(int*) variable->base_addr);
}
您可以在Fortran 2018 18.5.3中找到详细信息.
You can find details of this in Fortran 2018 18.5.3.
从本质上讲,这是一个描述符,其中包含Fortran实体的许多细节.在这里, base_addr
是数据的开始,但是您还将找到可分配的/指针/数据的状态,等级,范围,类型.
Essentially, however, this is a descriptor which has much of the detail of the Fortran entity. Here, base_addr
is the start of the data, but you'll also find allocatable/pointer/data status, rank, extents, type.
A,gfortran 4.9不支持此功能.如果完全受支持,它将仅是最新版本.
Alas, gfortran 4.9 doesn't support this. If it is supported at all, it will be in only very recent versions.
或者,您可以避免使用假定等级的假定类型实际参数,而使用 c_loc
传递参数的C地址.不太优雅,但得到了更广泛的支持:
Alternatively, you may avoid using an assumed-rank assumed-type actual argument and pass instead the C-address of the argument using c_loc
. Not quite so elegant, but more widely supported:
use, intrinsic :: iso_c_binding, only : c_loc, c_ptr, c_int
interface
subroutine show_value(variable) bind(c)
import c_ptr
type(c_ptr), value :: variable
end subroutine
end interface
integer(c_int), target :: x, y(3)
x = 12
y = [15, 17, 19]
call show_value(c_loc(x))
call show_value(c_loc(y))
end
但是,这留下了C函数如何知道如何处理参数的问题.
This, however, leaves the problem of how the C function knows what to do with the argument.
这篇关于将标量和数组(任何尺寸)从Fortran传递到C的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!