【问题标题】:What's the right way to pass a Fortran zero-length arrays to C?将 Fortran 零长度数组传递给 C 的正确方法是什么?
【发布时间】:2017-08-16 12:31:52
【问题描述】:

我有以下类型的子例程包装器将 Fortran 数组传递给ISO_C_BINDING-bound C 函数。

subroutine mysub( array )
  integer, dimension(:) :: array
  call f_mysub( size(array) , array(1) )
end subroutine

问题在于,如果数组的大小为 0,那么 array(1) 就会越界。处理这种情况的正确方法是什么?

一般来说,我无法避免通话,即使用if( size(array) > 0 ),因为通话可能对注册很重要,例如它实际上是一个类方法,与上面的签名自然不同,并且可以清除现有数组。

示例文件

C 例程是c_mysub.c

#include <stdio.h>
void c_mysub( size_t* size, int* arr )
{
    printf("size=%d\n",*size);
    for(size_t i=0; i<*size; ++i)
    {
        printf("element %d=%d\n",i,arr[i]);
    }
}

主Fortran文件是mysub.f90

module mysub_I
interface
subroutine f_mysub( size, arr) BIND(C,name="c_mysub")
    use,intrinsic :: ISO_C_BINDING
    integer(C_SIZE_T) :: size
    integer(C_INT) :: arr
end subroutine
end interface
end module

module mysub_M
use mysub_I
contains

subroutine mysub( array )
  use ISO_C_BINDING
  integer, dimension(:) :: array
  call f_mysub( int(size(array),C_SIZE_T) , array(1) )
end subroutine

end module

program main
use mysub_M
integer, allocatable :: x(:)

allocate( x(7) )
x=1

call mysub( x )

deallocate( x )
allocate( x(0) )

call mysub( x )

end

使用 gcc -c c_mysub.c 编译 C 和使用 gfortran -fbounds-check c_mysub.o mysub.f90 编译 Fortran,当您运行代码时会出现以下错误,在 size=0 的第二次调用中犹豫不决。

size=7
0:1
1:1
2:1
3:1
4:1
5:1
6:1
At line 18 of file mysub.f90
Fortran runtime error: Index '1' of dimension 1 of array 'array' above upper bound of 0

在关闭边界检查的情况下进行编译的行为符合预期。

size=7
0:1
1:1
2:1
3:1
4:1
5:1
6:1
size=0

【问题讨论】:

  • 如果数组为空,您可以暂时将数组维度设为 1。
  • ... 或者准备一个虚拟数组以备不时之需。
  • c_mysub的接口是什么?为什么你希望将一个标量数组元素传递给它,即使数组可能没有元素?
  • 只是为了备份 francescalus 你为什么不只是传递数组?
  • 通常你应该只通过array,而不是array(1)。如果您不显示真实代码,很难说更多。 array 存在不连续的风险,array(1) 将避免创建临时副本,这实际上可能是错误的。

标签: c arrays fortran fortran-iso-c-binding


【解决方案1】:

我看不出有任何理由将array(1) 作为实际参数传递。应该传递整个数组array

  call f_mysub( size(array) , array )

并且必须更改接口以传递数组而不仅仅是标量

  integer(C_INT) :: arr(*)

如果array 不连续,则传递第一个元素(甚至是数组参数)很容易导致不正确的行为——这在理论上是可能的,因为它假定为形状虚拟参数(使用(:))。

如果您传递整个数组和大小0,那么只需确保在 C 过程中实际上没有从指针中取消引用任何元素(如果写得好,应该已经是这种情况了)。

【讨论】:

  • 在这种情况下 f_mysub 是什么样的? c_mysub 将有 int[] arr 作为参数,对吧?
  • 现在才发现你接口错了,你确实得改正了。
  • C参数可以是数组也可以是指针,没关系。 int *array 很好。
  • 不是大小为零的数组不能与任何C数组互操作吗?
  • 我只是想检查一下。可能不是。但在实践中,无论传递什么地址,都不应该取消引用。甚至可以传递空指针。可以添加一个 if 并传递一个 c_null_pointer,但我认为这不值得。我只需要检查 Fortran 端没有发生任何不好的事情。
猜你喜欢
  • 1970-01-01
  • 2016-12-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-01-11
  • 1970-01-01
  • 1970-01-01
  • 2012-03-08
相关资源
最近更新 更多