将标量和数组(任何尺寸)从Fortran传递到C [英] Passing both scalars and arrays (of any dimensions) from Fortran to C

查看:69
本文介绍了将标量和数组(任何尺寸)从Fortran传递到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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆