You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

传递带负步长的可分配character(:)切片致GFortran段错误,原因何在?

问题:为何以下Fortran程序会出现段错误?是编译器问题,还是违反了Fortran标准?
! gfortran -fcheck=all arrays10.f90 && ./a
! GNU Fortran (GCC) 11.4.0
program arrays10
    implicit none

    ! 不可分配变量不会触发段错误。
    !integer :: a(3)
    !character(5) :: b(3)

    integer, allocatable :: a(:)
    character(:), allocatable :: b(:)

    a = [1,2,3]
    b = [ character(5) :: "one", "two", "three"]

    print *, "Test integer array"
    print *, "loc: ", loc(a)
    call test01(a)
    call test01(a(size(a):1:-1))
    print *

    print *, "Test character(*) (:)"
    print *, "loc: ", loc(b)
    call test02(b)
    ! 仅在负步长时触发段错误
    call test02(b(size(b):1:-1))
    print *

    print *, "Test character(*) (*)"
    print *, "loc: ", loc(b)
    call test03(b)
    ! 仅在负步长时触发段错误
    call test03(b(size(b):1:-1))
    print *

    contains

    subroutine test01(a)
        ! 无段错误

        ! 要求连续内存,会创建临时数组
        !integer, intent(in) :: a(3)

        ! 继承步长,不创建临时数组
        integer, intent(in) :: a(:)

        integer i

        print *, "testing: ", rank(a), size(a)
        ! 但loc()显然有布局要求
        ! 会创建临时数组
        print *, loc(a)
        do i = 1, size(a)
            print *, a(i)
        end do
        print *
    end subroutine test01

    subroutine test02(a)
        ! 触发以下错误:
        ! Segmentation fault - 无效内存引用

        ! 强制可分配参数,无实用价值
        !character(:), allocatable, intent(in) :: a(:)

        ! 这两种都应创建临时数组,但未看到警告。
        ! 因为段错误会在(取消注释时)此处触发。
        !character(*), intent(in) :: a(3)
        !character(5), intent(in) :: a(3)

        ! 不应创建临时数组。
        character(*), intent(in) :: a(:)

        integer i

        print *, "testing: ", rank(a), size(a), len(a(1))
        ! 再次强制创建临时数组会触发相同段错误
        !print *, loc(a)
        ! 按原顺序迭代仍会触发段错误。
        !do i = size(a), 1, -1
        do i = 1, size(a)
            ! 在此处(第一次迭代)触发段错误:无效内存引用
            print *, "          ", a(i)
        end do
        print *
    end subroutine test02

    subroutine test03(a)
        ! 结果与test02相同

        ! 两种情况都会在此处触发段错误
        character(*), intent(in) :: a(*)
        !character(*), intent(in) :: a(1)

        print *, "testing: ", rank(a), size(a(:3)), len(a(1))
        print *, loc(a)
        print *
    end subroutine test03

end program arrays10

分析与解答

结论:这是gfortran编译器的bug,而非违反Fortran标准

现象总结

  • 传递可分配字符数组的负步长切片(如b(size(b):1:-1))给子例程时触发段错误;
  • 整数数组的相同操作无异常;
  • 使用非可分配的字符数组时,负步长切片不会触发错误。

原因解释

  1. 标准合规性确认:你的代码完全符合Fortran标准。根据标准,传递非连续数组切片(负步长属于非连续)给假设形状(a(:))或假设大小(a(*))的哑元是合法操作,编译器需正确处理(要么生成临时连续数组,要么通过数组描述符支持非连续访问)。
  2. gfortran特定缺陷:在GCC 11.4.0版本的gfortran中,存在针对可分配字符数组非连续切片的处理bug。当传递这类切片时,编译器生成的内存访问代码存在逻辑错误,导致程序尝试访问无效内存地址,进而触发段错误。
    • 整数数组未出现问题,是因为gfortran对整数类型的非连续切片处理逻辑正确;
    • 非可分配字符数组无问题,说明bug仅与可分配字符数组的切片内存管理相关。

验证与解决方案

  • 升级编译器:尝试将gfortran升级到GCC 12或更高版本,这类字符数组切片的bug在后续版本中已被修复;
  • 临时规避方案:在传递负步长切片前,手动创建临时连续数组(如call test02([b(size(b):1:-1)])),强制编译器生成合法的连续内存副本。

内容的提问来源于stack exchange,提问作者user19087

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.01 09:15:26