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

Fortran中子程序调用传递切片数组时如何避免创建临时数组?

Fortran数组切片调用子程序时的临时数组警告问题

问题描述

我编写了如下Fortran子程序:

subroutine invertCell( a1vec,a2vec,a3vec, rlvec ) !(icluster)
    implicit none
    ! ======= Parameters
    real, dimension (3),  intent(in)  :: a1vec, a2vec, a3vec
    real, dimension (3,3),intent(out) :: rlvec
    ! ... Body ...
end subroutine

当我从3×3矩阵中按行切片作为参数调用该子程序时:

real, dimension (3,3) :: ervec
real, dimension (3,3) :: elvec
...
call invertCell( ervec(1,:),ervec(2,:),ervec(3,:), elvec )

会收到警告:Fortran runtime warning: An array temporary was created。

我可以通过显式创建临时数组规避警告,但写法很繁琐:

real, dimension (3)     :: ervec1,ervec2,ervec3
...
ervec1(:) = ervec(1,:)
ervec2(:) = ervec(2,:)
ervec3(:) = ervec(3,:)
call invertCell( ervec1,ervec2,ervec3, elvec )

我有C/C背景,C/C中数组可通过指针算术实现无复制切片,疑惑Fortran为何无法做到。


原因分析

Fortran采用列主序存储数组,即矩阵的列是连续内存块,而行是分散的非连续内存。你的子程序形参a1vec是固定大小的连续一维数组,当传入ervec(1,:)(矩阵的第一行,非连续内存)时,编译器为了满足形参对连续内存的要求,会自动创建临时数组,把切片数据复制进去,这就是警告的来源。

而C/C++是行主序存储,矩阵的行是连续内存,且函数参数可直接接受指针,因此能直接传递行切片的地址,无需复制。


无需显式临时数组的解决方案

1. 修改子程序为接受假定形状数组(Fortran 2003+)

将形参改为假定形状数组(dimension(:)),这类数组的描述符包含内存布局信息,可直接处理非连续切片,无需创建临时数组:

subroutine invertCell( a1vec,a2vec,a3vec, rlvec ) !(icluster)
    implicit none
    ! ======= Parameters
    real, dimension(:),  intent(in)  :: a1vec, a2vec, a3vec
    real, dimension(3,3),intent(out) :: rlvec
    ! 可选:添加输入长度校验,避免非法参数
    if (size(a1vec)/=3 .or. size(a2vec)/=3 .or. size(a3vec)/=3) then
        error stop "invertCell: Input vectors must be length 3"
    end if
    ! ... Body ...
end subroutine

修改后直接用原调用方式即可,不会再产生临时数组警告。

2. 调整数组存储为列主序匹配形式

如果允许调整数据存储方式,将矩阵的行数据转为列存储,这样切片列时是连续内存,直接传入即可:

real, dimension(3,3) :: ervec, elvec
! 将原行数据转存为列(示例)
ervec(:,1) = [1.0, 2.0, 3.0]  ! 原第一行
ervec(:,2) = [4.0, 5.0, 6.0]  ! 原第二行
ervec(:,3) = [7.0, 8.0, 9.0]  ! 原第三行

! 调用时传入列切片(连续内存)
call invertCell( ervec(:,1), ervec(:,2), ervec(:,3), elvec )

3. 使用指针关联切片(Fortran 90+)

用指针直接关联矩阵的行切片,指针会指向原数组内存,无需复制:

real, dimension(3,3) :: ervec, elvec
real, dimension(:), pointer :: er1, er2, er3

! 指针关联到矩阵的行
er1 => ervec(1,:)
er2 => ervec(2,:)
er3 => ervec(3,:)

call invertCell( er1, er2, er3, elvec )

! 可选:使用后清空指针,避免悬垂指针
nullify(er1, er2, er3)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 08:09:23