将 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 过程中的指针取消引用(如果写得好的话应该已经是这种情况了)。
我有以下类型的子例程包装器,用于将 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 过程中的指针取消引用(如果写得好的话应该已经是这种情况了)。