将 Fortran 零长度数组传递给 C 的正确方法是什么?

What's the right way to pass a Fortran zero-length arrays to C?

我有以下类型的子例程包装器,用于将 Fortran 数组传递给 ISO_C_BINDING 绑定的 C 函数。

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

问题在于,如果数组的大小为 0,则 array(1) 超出范围。处理这种情况的正确方法是什么?

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

示例文件

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

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

  call f_mysub( size(array) , array )

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

  integer(C_INT) :: arr(*)

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

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