公用块中延迟长度字符数组的替代方案(gfortran编译崩溃)
问题背景
调用C函数分配Fortran动态数组时,整数、实数、逻辑类型均正常工作,但将动态长度字符串指针(character(len=:), pointer)放入公用块会触发gfortran内部编译器错误,涉及版本包括4.8.5、8.5.0、11.3.1,疑似关联Bug #55735。简化崩溃代码如下:
subroutine sub1() character(len=:), pointer :: local character(len=:), pointer :: comm common /commie/ comm comm = local return end
核心需求
寻找可放入公用块的动态大小字符串数组替代声明,需满足:
- 兼容现有使用
character(kind=ucs4, len=xxx) stringarray1(yyy)的Fortran代码 - 禁止使用
character(kind=ucs4, len=:) stringarray1(:)形式的声明
现有整数类型的可行实现参考:
SUBROUTINE shob_arrI(ptr, decl, sz, grp) USE ISO_C_BINDING integer, pointer :: ptr(:) character*(*) decl integer*8 sz integer, pointer :: grp END SUBROUTINE shob_arrI .... integer, pointer :: grpX integer, pointer :: i1(:) common /grpX/ i1 call shob_arrI(i1, 'integer i1(7)', 0_8, grpX)
其中shob_arrI为C函数,负责解析声明语句、构建gfortran的GFC_ARRAY_DESCRIPTOR结构,并将数组映射到共享内存供多进程访问。
可行解决方案
方案1:固定长度字符数组指针(推荐,兼容现有代码)
gfortran支持将固定长度的字符数组指针放入公用块,不会触发编译错误。可通过C函数动态指定每个字符串的长度xxx和数组维度yyy,构建对应数组的描述符后赋值给Fortran指针。
实现步骤:
Fortran端声明:
use, intrinsic :: iso_fortran_env, only: ucs4 character(kind=ucs4), pointer :: stringarray1(:) common /comm_str/ stringarray1这里省略
len属性,实际每个元素的长度由C函数构建的GFC_ARRAY_DESCRIPTOR动态设置。对应C函数接口:
参考整数版本编写字符串专用的shob_arrC,解析声明语句(如'character(ucs4) stringarray1(5,len=10)'),计算每个元素的字节大小(10 * sizeof(ucs4)),构建符合gfortran要求的数组描述符并映射到共享内存。调用示例:
SUBROUTINE shob_arrC(ptr, decl, sz, grp) USE ISO_C_BINDING use, intrinsic :: iso_fortran_env, only: ucs4 character(kind=ucs4), pointer :: ptr(:) character*(*) decl integer*8 sz integer, pointer :: grp END SUBROUTINE shob_arrC
....
integer, pointer :: grpX
character(kind=ucs4), pointer :: str1(:)
common /grpX/ str1
call shob_arrC(str1, 'character(ucs4) str1(5,len=10)', 0_8, grpX)
现有使用`character(kind=ucs4, len=10) str1(5)`的代码可直接使用`str1`指针,无需修改。 ### 方案2:派生类型封装(需调整现有代码) 若需支持每个字符串长度不同的场景,可通过派生类型封装字符串指针和长度,再将派生类型的数组指针放入公用块: ```fortran use, intrinsic :: iso_fortran_env, only: ucs4 type :: StrPtr character(kind=ucs4, len=:), pointer :: str => null() integer :: length = 0 end type StrPtr type(StrPtr), pointer :: stringarray1(:) common /comm_str/ stringarray1
此方案需修改现有代码,将stringarray1(i)替换为stringarray1(i)%str,仅适用于允许调整现有代码的场景。
内容的提问来源于stack exchange,提问作者Geoff

