c - 将标量和数组(任何维度)从 Fortran 传递到 C
问题描述
我有以下名为的 Fortran 子例程show_value
,它调用名为的 C 函数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 子例程在将标量传递给它时运行良好。例子:
INTEGER :: x
x = 12
call show_value(x)
这将调用 C 函数show_value
和 print 12
,这是正确的。
现在,根据 Fortran 文档,如果要启用子程序show_value
来接收数组(任何维度的)而不仅仅是标量,则该行TYPE(*) :: variable
应更改为TYPE(*), DIMENSION(..) :: variable
.
进行此更改后,在执行以下 Fortran 代码时:
INTEGER, DIMENSION(3) :: y
y(1) = 15
y(2) = 17
y(3) = 19
call show_value(y)
C 函数show_value
不再打印正确的消息(即打印随机数)。此外,我发现 C 函数接收到的地址比原始地址低 528(在 Fortran 中)。要确认这一点:
void show_value(const void *variable)
{
printf("%d\n", *(int *) (variable + 528));
}
...打印15
(正确的数字)。
知道这里发生了什么吗?
环境:Ubuntu 14.04 64 位,gfortran 4.9
解决方案
尽管您的第一种情况(带有标量参数)可以与参数正确匹配void*
,但当调用的参数是假定等级(type(*), dimension(..) :: variable
表示)时,Fortran 过程不能与具有相应形式参数的 C 过程互操作const void *variable
。
相反,有必要使用该CFI_cdesc_t
机制:
#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 中找到详细信息。
然而,本质上,这是一个包含 Fortran 实体的大部分细节的描述符。这里base_addr
是数据的开始,但您还会发现可分配/指针/数据状态、等级、范围、类型。
唉,gfortran 4.9 不支持这个。如果它完全受支持,它只会出现在最近的版本中。
或者,您可以避免使用假定等级的假定类型实际参数,而是使用c_loc
. 不太优雅,但得到更广泛的支持:
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 函数如何知道如何处理参数的问题。
推荐阅读
- c# - 如何将变量值“传递”给 JSON 动态对象?
- html - 如何绘制像梯形这样的html css形状
- json - URLSession/JSONSerialization 发回一个不是 json 的对象
- .htaccess - .htaccess 显示 500 内部服务器错误而不是预期的 404 错误
- javascript - 为什么动漫 js 只播放第一个动态“添加”动画到时间轴?
- swift - 如何从内存中卸载 GMSMapView?
- css - 具有不必要的白色背景的范围滑块
- eslint - 如何将 eslint 配置为与 svelte 和 postcss-nesting 一起使用?
- reactjs - 如何设置 npm 包的依赖项以支持树抖动
- sass - 实时服务器不能很好地与 Google Drive(服务器端文件)一起工作,有没有办法让它工作?