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

如何初始化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标准,直接访问未关联的指针会触发访问违规。

具体修复步骤

  1. 修正派生类型名称拼写错误:主程序中定义type TxT,但结束时写成end type Txt(大小写错误),这会导致编译错误,需修正为end type TxT。

  2. 为指针分配有效内存:
    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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.17 00:12:06