C_FUNLOC 的结果是标量还是数组?
Is the result of C_FUNLOC a scalar or an array?
我试图将一些 Fortran 子例程表示为 c_funptr
(void *
),以通过我试图调用 c_funloc
的 fdict library. Following GCC docs here 创建一个字典。然而 gfortran 似乎 return 一个 c_funptr
数组而不是一个标量值。
这是编译器中的错误还是我遗漏了一些重要的东西?
来自gfortran -v
的输出:
COLLECT_GCC=gfortran
COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-pc-linux-gnu/8.3.0/lto-wrapper
Target: x86_64-pc-linux-gnu
Configured with: /build/gcc/src/gcc/configure --prefix=/usr --libdir=/usr/lib --libexecdir=/usr/lib --mandir=/usr/share/man --infodir=/usr/share/info --with-bugurl=https://bugs.archlinux.org/ --enable-languages=c,c++,ada,fortran,go,lto,objc,obj-c++ --enable-shared --enable-threads=posix --enable-libmpx --with-system-zlib --with-isl --enable-__cxa_atexit --disable-libunwind-exceptions --enable-clocale=gnu --disable-libstdcxx-pch --disable-libssp --enable-gnu-unique-object --enable-linker-build-id --enable-lto --enable-plugin --enable-install-libiberty --with-linker-hash-style=gnu --enable-gnu-indirect-function --enable-multilib --disable-werror --enable-checking=release --enable-default-pie --enable-default-ssp --enable-cet=auto
Thread model: posix
gcc version 8.3.0 (GCC)
我也尝试过使用 ifort(版本 19.0.2.187)并且它提供了所需的行为(见下文)。
MWE:
! = minimum.f90 =
module test
use iso_c_binding
implicit none
interface test_funptr
module procedure test_funptr0
module procedure test_funptr1
end interface test_funptr
contains
subroutine test_funptr0(fp)
type(c_funptr) :: fp
write(*,*) "fp0!"
end subroutine test_funptr0
subroutine test_funptr1(fp)
type(c_funptr), dimension(:) :: fp
write(*,*) "fp1!", shape(fp)
end subroutine test_funptr1
function bar(x) result(y) bind(c)
real(c_double) :: x
real(c_double) :: y
y = -x**2 + x + 1
end function bar
end module test
program main
use iso_c_binding
use test
implicit none
call test_funptr(c_funloc(bar))
end program main
用 gfortran minimum.f90 -o min
编译
各处的预期输出:
fp0
实际行为:fp1
gfortran 的形状为零,英特尔编译器的 fp0
。
也许我只是缺少 gfortran 的正确选项?
内部模块 iso_c_binding
的函数 c_funloc
由 Fortran 标准指定,函数结果为 c_funptr
类型的标量(Fortran 2018,18.2.3.5,类似在 Fortran 2003 和 Fortran 2008 中)。
当程序本身符合 Fortran 标准时,将函数结果设为数组违反了 Fortran 标准。
但是,在这种情况下,gfortran 没有提供数组函数结果:您可以使用像
这样简单的东西来测试它
print*, SHAPE(C_FUNLOC(bar))
相反,gfortran 无法将通用过程 test_funptr
正确解析为特定 test_funptr0
。
也考虑一下情况
use, intrinsic :: iso_c_binding, only : c_funptr, c_null_funptr
use test, only : test_funptr, test_funptr1
type(c_funptr) :: ptr = C_NULL_FUNPTR
call test_funptr(ptr)
call test_funptr1(ptr)
end
gfortran 8 错误地解析了泛型并允许直接调用 test_funptr1
.
我将尝试总结讨论(在某种程度上)并解决最初的问题——使用函数指针从 fdict 填充字典。该字典支持多种值类型,包括 c_funptr
。
通过 с_funloc
将 Fortran 过程转换为 type(c_funptr)
并附加到字典似乎是明智的。
但是,由于 gfortran 中的问题,调用了错误的子例程并且函数指针存储为 type(c_funptr), dimension(:)
。尝试将它们作为标量检索会导致分段错误。为了克服它,你可以创建一个函数指针数组,只包含一个元素。
像这样:
type(dictionary_t) :: fdict
fdict = ('bar' .kv. (/c_funloc(bar)/) ) //&
& ('baz' .kv. (/c_funloc(baz)/) )
要检索函数返回,您可以下标指针数组并将其转换为 Fortran 过程指针,如以下代码片段所示
type(c_funptr) :: cfp(1)
procedure(bar), pointer :: ffp => null()
call assign(cfp, dict, key) # generic from fdict
call c_f_procpointer(cfp(1), ffp)
可以找到包含使用示例的完整源代码here。
此解决方案也适用于 ifort。两种变体都产生与上述示例相似的输出:
baz [fp1] (...)
bar [fp1] (...)
-1.000 1.000 -1.000
-1.000 -2.000 -10.000
我试图将一些 Fortran 子例程表示为 c_funptr
(void *
),以通过我试图调用 c_funloc
的 fdict library. Following GCC docs here 创建一个字典。然而 gfortran 似乎 return 一个 c_funptr
数组而不是一个标量值。
这是编译器中的错误还是我遗漏了一些重要的东西?
来自gfortran -v
的输出:
COLLECT_GCC=gfortran
COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-pc-linux-gnu/8.3.0/lto-wrapper
Target: x86_64-pc-linux-gnu
Configured with: /build/gcc/src/gcc/configure --prefix=/usr --libdir=/usr/lib --libexecdir=/usr/lib --mandir=/usr/share/man --infodir=/usr/share/info --with-bugurl=https://bugs.archlinux.org/ --enable-languages=c,c++,ada,fortran,go,lto,objc,obj-c++ --enable-shared --enable-threads=posix --enable-libmpx --with-system-zlib --with-isl --enable-__cxa_atexit --disable-libunwind-exceptions --enable-clocale=gnu --disable-libstdcxx-pch --disable-libssp --enable-gnu-unique-object --enable-linker-build-id --enable-lto --enable-plugin --enable-install-libiberty --with-linker-hash-style=gnu --enable-gnu-indirect-function --enable-multilib --disable-werror --enable-checking=release --enable-default-pie --enable-default-ssp --enable-cet=auto
Thread model: posix
gcc version 8.3.0 (GCC)
我也尝试过使用 ifort(版本 19.0.2.187)并且它提供了所需的行为(见下文)。
MWE:
! = minimum.f90 =
module test
use iso_c_binding
implicit none
interface test_funptr
module procedure test_funptr0
module procedure test_funptr1
end interface test_funptr
contains
subroutine test_funptr0(fp)
type(c_funptr) :: fp
write(*,*) "fp0!"
end subroutine test_funptr0
subroutine test_funptr1(fp)
type(c_funptr), dimension(:) :: fp
write(*,*) "fp1!", shape(fp)
end subroutine test_funptr1
function bar(x) result(y) bind(c)
real(c_double) :: x
real(c_double) :: y
y = -x**2 + x + 1
end function bar
end module test
program main
use iso_c_binding
use test
implicit none
call test_funptr(c_funloc(bar))
end program main
用 gfortran minimum.f90 -o min
各处的预期输出:
fp0
实际行为:fp1
gfortran 的形状为零,英特尔编译器的 fp0
。
也许我只是缺少 gfortran 的正确选项?
内部模块 iso_c_binding
的函数 c_funloc
由 Fortran 标准指定,函数结果为 c_funptr
类型的标量(Fortran 2018,18.2.3.5,类似在 Fortran 2003 和 Fortran 2008 中)。
当程序本身符合 Fortran 标准时,将函数结果设为数组违反了 Fortran 标准。
但是,在这种情况下,gfortran 没有提供数组函数结果:您可以使用像
这样简单的东西来测试它print*, SHAPE(C_FUNLOC(bar))
相反,gfortran 无法将通用过程 test_funptr
正确解析为特定 test_funptr0
。
也考虑一下情况
use, intrinsic :: iso_c_binding, only : c_funptr, c_null_funptr
use test, only : test_funptr, test_funptr1
type(c_funptr) :: ptr = C_NULL_FUNPTR
call test_funptr(ptr)
call test_funptr1(ptr)
end
gfortran 8 错误地解析了泛型并允许直接调用 test_funptr1
.
我将尝试总结讨论(在某种程度上)并解决最初的问题——使用函数指针从 fdict 填充字典。该字典支持多种值类型,包括 c_funptr
。
通过 с_funloc
将 Fortran 过程转换为 type(c_funptr)
并附加到字典似乎是明智的。
但是,由于 gfortran 中的问题,调用了错误的子例程并且函数指针存储为 type(c_funptr), dimension(:)
。尝试将它们作为标量检索会导致分段错误。为了克服它,你可以创建一个函数指针数组,只包含一个元素。
像这样:
type(dictionary_t) :: fdict
fdict = ('bar' .kv. (/c_funloc(bar)/) ) //&
& ('baz' .kv. (/c_funloc(baz)/) )
要检索函数返回,您可以下标指针数组并将其转换为 Fortran 过程指针,如以下代码片段所示
type(c_funptr) :: cfp(1)
procedure(bar), pointer :: ffp => null()
call assign(cfp, dict, key) # generic from fdict
call c_f_procpointer(cfp(1), ffp)
可以找到包含使用示例的完整源代码here。
此解决方案也适用于 ifort。两种变体都产生与上述示例相似的输出:
baz [fp1] (...)
bar [fp1] (...)
-1.000 1.000 -1.000
-1.000 -2.000 -10.000