如何正确地将 C 字符串读入未指定长度的 Fortran 字符串?
How to correctly read a C-string into a Fortran string of unspecified length?
以下函数应该将 C 字符串转换为 Fortran 字符串,并且在 Release 版本中工作正常,但在 Debug 中不行:
! Helper function to generate a Fortran string from a C char pointer
function get_string(c_pointer) result(f_string)
use, intrinsic :: iso_c_binding
implicit none
type(c_ptr), intent(in) :: c_pointer
character(len=:), allocatable :: f_string
integer(c_size_t) :: l_str
character(len=:), pointer :: f_ptr
interface
function c_strlen(str_ptr) bind ( C, name = "strlen" ) result(len)
use, intrinsic :: iso_c_binding
type(c_ptr), value :: str_ptr
integer(kind=c_size_t) :: len
end function c_strlen
end interface
l_str = c_strlen(c_pointer)
call c_f_pointer(c_pointer, f_ptr)
f_string = f_ptr(1:l_str)
end function get_string
但是,c_f_pointer
似乎并没有告诉 Fortran 字符串指针,f_ptr
,它指向的字符串的长度。在调试版本中,边界检查处于活动状态,这会导致
Fortran runtime error: Substring out of bounds: upper bound (35) of 'f_ptr' exceeds string length (0)
我正在使用 gcc (Ubuntu 9.3.0-17ubuntu1~20.04) 9.3.0
并将标准设置为 2008。
我的问题:有没有什么方法可以在不更改声明的情况下告诉 f_ptr
它的长度,或者我在这里做的事情从根本上是错误的?
如果我指定形状,似乎 运行 是正确的,但为此 f_ptr
需要是一个数组:
character(len=:), allocatable :: f_string
character(len=1), dimension(:), pointer :: f_ptr
...
call c_f_pointer(c_pointer, f_ptr, [l_str])
但是,我找不到将等级为 1 的字符串转换为 character(len=:), allocatable :: f_string
的方法,后者显然等级为 0。
我的第二个问题:有什么方法可以把f_ptr
的数据转成这个例子中的f_string
吗?
不能使用c_f_pointer
设置Fortran字符指针的长度(F2018, 18.2.3.3):
FPTR shall be a pointer, shall not have a deferred type parameter [...]
因此不能使用延迟长度的字符标量(或数组)(长度是类型参数)。
您确实可以使用延迟 shape 字符数组作为 fptr
,然后使用任何 将该数组的元素复制到标量(如前所述,排名 0)。
例如,使用子字符串赋值(在显式分配延迟长度标量之后):
allocate (character(l_str) :: f_string)
do i=1,l_str
f_string(i:i)=fptr(i)
end
或者考虑是否可以简单地使用字符数组而不是复制到标量。
以下函数应该将 C 字符串转换为 Fortran 字符串,并且在 Release 版本中工作正常,但在 Debug 中不行:
! Helper function to generate a Fortran string from a C char pointer
function get_string(c_pointer) result(f_string)
use, intrinsic :: iso_c_binding
implicit none
type(c_ptr), intent(in) :: c_pointer
character(len=:), allocatable :: f_string
integer(c_size_t) :: l_str
character(len=:), pointer :: f_ptr
interface
function c_strlen(str_ptr) bind ( C, name = "strlen" ) result(len)
use, intrinsic :: iso_c_binding
type(c_ptr), value :: str_ptr
integer(kind=c_size_t) :: len
end function c_strlen
end interface
l_str = c_strlen(c_pointer)
call c_f_pointer(c_pointer, f_ptr)
f_string = f_ptr(1:l_str)
end function get_string
但是,c_f_pointer
似乎并没有告诉 Fortran 字符串指针,f_ptr
,它指向的字符串的长度。在调试版本中,边界检查处于活动状态,这会导致
Fortran runtime error: Substring out of bounds: upper bound (35) of 'f_ptr' exceeds string length (0)
我正在使用 gcc (Ubuntu 9.3.0-17ubuntu1~20.04) 9.3.0
并将标准设置为 2008。
我的问题:有没有什么方法可以在不更改声明的情况下告诉 f_ptr
它的长度,或者我在这里做的事情从根本上是错误的?
如果我指定形状,似乎 运行 是正确的,但为此 f_ptr
需要是一个数组:
character(len=:), allocatable :: f_string
character(len=1), dimension(:), pointer :: f_ptr
...
call c_f_pointer(c_pointer, f_ptr, [l_str])
但是,我找不到将等级为 1 的字符串转换为 character(len=:), allocatable :: f_string
的方法,后者显然等级为 0。
我的第二个问题:有什么方法可以把f_ptr
的数据转成这个例子中的f_string
吗?
不能使用c_f_pointer
设置Fortran字符指针的长度(F2018, 18.2.3.3):
FPTR shall be a pointer, shall not have a deferred type parameter [...]
因此不能使用延迟长度的字符标量(或数组)(长度是类型参数)。
您确实可以使用延迟 shape 字符数组作为 fptr
,然后使用任何
例如,使用子字符串赋值(在显式分配延迟长度标量之后):
allocate (character(l_str) :: f_string)
do i=1,l_str
f_string(i:i)=fptr(i)
end
或者考虑是否可以简单地使用字符数组而不是复制到标量。