如何初始化Fortran派生类型变量?适配Intel 19编译问题
问题描述
我熟悉F77、掌握C#面向对象编程,刚接触Fortran的派生类型(derived-type)。有一份研究生编写的代码在Intel 11编译器下可正常运行,但切换到Intel 19编译器后报错,问题出在初始化派生类型指针变量时出现访问违规,无法执行后续代码。以下是最小可复现示例(MWE):
主程序代码
program DerivedType ! investigate lines of code from large code "fabrics" that I do not understand use strength_mod_test ! define and initialize array X double precision, dimension(6) :: X = (/1,2,3,4,5,6/) ! just data, not PARAMETER. Values can be modified in the code. ! type (object) definition type One double precision :: small(6) ! the data in this type ! pointer :: Ff(:,:) ! Pointer is not permitted as a statement within a derived-type-def. end type One type TxT double precision :: small(3,3) ! so that any var of type "type" has the correct size %small, depending of the "type" end type Txt ! Why the constructor is not inside the type definition. ! Because "pointer" is not permitted inside a type def. ! You have to write the constructor outside the type def. ! Variables must be defined before any executable code. ! Define variables of type "type" using a constructor. ! Cannot be defined inside the type if "pointer" is used. ! "Type" constructor outside the type def. Note the () type(One), pointer :: Ff(:,:), Fw(:,:), sigmaf123(:,:), sigmaw123(:,:) type(TxT), pointer :: Df(:,:), Dw(:,:), Omega_f(:,:), Omega_w(:,:) ! local variables integer i,j ! Initialize type variables ! Df is of type TxT, and in type TxT, small is (3,3) ! Df%small = 0 ! A component cannot be an array if the encompassing structure is an array.[SMALL] ! so I do this do i=1,3 do j=1,3 Df(i,j)%small = 0.d0 ! why access violation?! enddo end do ! TYPE (TxT) :: Df_new = TxT (Df = 0) does not work either ! I can't execute next statement until I initialize Df(i,j)%small and signf123(i,j)%small Ff(i,j)%small = F_function (X, Df(i,j)%small, sigmaf123(i,j)%small) end program
模块代码
module strength_mod_test contains function F_function (R, D, sig) double precision, dimension(6) :: F_function ! rank=1 double precision, dimension(6), intent(in) :: R, sig ! rank=1 double precision, dimension(3,3), intent(in) :: D ! rank=2 F_function = 0.d0 if (D(1,1) == 0.d0 .AND. sig(1) > 0.d0) then F_function(1) = sig(1)/R(1) end if if (D(2,2) == 0.d0 .AND. sig(2) > 0.d0) then F_function(2) = sig(2)/R(2) end if if (D(3,3) == 0.d0 .AND. sig(3) > 0.d0) then F_function(3) = sig(3)/R(3) end if if (D(2,2) == 0.d0 .OR. D(3,3) == 0.d0) then F_function(4) = abs(sig(4))/R(4) end if if (D(3,3) == 0.d0) then F_function(5) = abs(sig(5))/R(5) end if if (D(2,2) == 0.d0) then F_function(6) = abs(sig(6))/R(6) end if end function F_function end module
问题分析与修复方案
核心问题是指针变量未关联到有效的内存空间:Intel 11编译器对未初始化指针的检查较宽松,而Intel 19编译器严格遵循Fortran标准,直接访问未关联的指针会触发访问违规。
具体修复步骤
修正派生类型名称拼写错误:主程序中定义
type TxT,但结束时写成end type Txt(大小写错误),这会导致编译错误,需修正为end type TxT。为指针分配有效内存:
Fortran的指针必须先关联到已分配的内存或目标变量才能使用,不能直接像普通变量一样赋值。推荐两种修复方式:
方式一:用可分配数组替代指针(简单高效,无需指针特性时优先选择)
program DerivedType use strength_mod_test ! define and initialize array X double precision, dimension(6) :: X = (/1,2,3,4,5,6/) ! type definition type One double precision :: small(6) end type One type TxT double precision :: small(3,3) end type TxT ! 修正拼写错误 ! 使用可分配数组替代指针,无需手动管理关联 type(One), allocatable :: Ff(:,:), sigmaf123(:,:) type(TxT), allocatable :: Df(:,:) ! local variables integer i,j ! 为可分配数组分配内存(维度根据实际需求调整) allocate(Ff(3,3), sigmaf123(3,3)) allocate(Df(3,3)) ! Initialize type variables do i=1,3 do j=1,3 Df(i,j)%small = 0.d0 sigmaf123(i,j)%small = 0.d0 ! 初始化sigmaf123,避免后续访问未初始化数据 enddo end do ! 执行函数调用(循环内操作,避免原代码的数组越界问题) do i=1,3 do j=1,3 Ff(i,j)%small = F_function(X, Df(i,j)%small, sigmaf123(i,j)%small) enddo end do ! 释放内存(程序结束时编译器会自动释放,显式释放更规范) deallocate(Ff, sigmaf123, Df) end program
方式二:保留指针并关联到目标内存
program DerivedType use strength_mod_test double precision, dimension(6) :: X = (/1,2,3,4,5,6/) type One double precision :: small(6) end type One type TxT double precision :: small(3,3) end type TxT ! 定义目标数组(带target属性) type(One), target :: Ff_target(3,3), sigmaf123_target(3,3) type(TxT), target :: Df_target(3,3) ! 定义指针并关联到目标 type(One), pointer :: Ff(:,:), sigmaf123(:,:) type(TxT), pointer :: Df(:,:) integer i,j ! 关联指针到目标内存 Ff => Ff_target sigmaf123 => sigmaf123_target Df => Df_target ! 初始化 do i=1,3 do j=1,3 Df(i,j)%small = 0.d0 sigmaf123(i,j)%small = 0.d0 enddo end do ! 函数调用 do i=1,3 do j=1,3 Ff(i,j)%small = F_function(X, Df(i,j)%small, sigmaf123(i,j)%small) enddo end do end program
补充说明
- Fortran 90及以后标准支持派生类型内部包含指针,原代码中“Pointer is not permitted as a statement within a derived-type-def”的注释错误,只是含指针的派生类型无法用默认构造函数初始化指针成员,需手动关联或自定义构造函数。
- 原代码循环结束后直接使用
i=4,j=4的值访问数组,会触发越界,修复后的代码改为嵌套循环内调用函数,避免该问题。
内容的提问来源于stack exchange,提问作者Echeban
相关产品推荐
相关产品推荐

