为什么Fortran代码会出现分段错误?

时间:2018-04-07 05:58:00

标签: segmentation-fault fortran

下面的fortran代码会出现分段错误。 但是,当我将print*,pow(10_8,i)修改为print*,pow(j,i)时,它可以在没有呕吐分段错误的情况下工作。为什么?这很奇怪。

module mdl
    implicit none
    integer(kind=8)::n,m=1000000007
    integer(kind=8)::p(1000),k(1000),div(10000000)
contains

    integer(kind=8) function pow(a,pwr)
        implicit none
        integer(kind=8)::a,pwr
        integer(kind=8)::cur
        cur=pwr
        pow=1
        do while(cur>0)
            if(mod(cur,2)==1)pow=mod(pow*a,m)
            a=MOD(a*a,m)
            cur=cur/2
        end do
    end function
end module



program main
    use mdl
    implicit none
    integer(kind=8)::i,j,l,r,x,y
    i=2
    j=10
    print*,pow(10_8,i)
    print*,i
end program

1 个答案:

答案 0 :(得分:3)

这里的问题是函数a的参数pow。在函数中,参数a(可能)在行

上被修改
            a=MOD(a*a,m)

引用函数时的实际参数10_8是一个不能修改的文字常量。这是你的程序失败的时候。当您使用print*,pow(j,i)时,j是一个可以修改 的变量,而您的程序也不会失败。

这里有很多复杂的东西,我在这个答案中没有完全解释(你可以搜索其他问题)。一个主题是参数关联,它解释了为什么要尝试修改常量10_8。但是,我会对dummy argument intents说些什么。

伪参数a没有指定意图。当您打算在进入函数时使用a的值并且您希望(可能)修改它时,适当的意图将是intent(inout)。如果你应用它,你会发现你的编译器抱怨该分配线。

没有意图,例如在问题的情况下,是一种可以接受的东西。这有certain meaning。也就是说,是否可以修改a取决于引用该函数时的实际参数是否可以。当实际参数为10_8时,它可能不会;它可能是j

至关重要的是,编译器不负责,但是你的责任是检查程序是否在这里做了一些事情。

现在,即使您被允许,也可能不想修改实际参数j。你有几个选择:

  • 您可以制作临时本地副本(并将a标记为intent(in)),这可以安全修改;
  • 您可以使用value属性制作输入数据的匿名可修改副本。

您首先使用cur=pwr执行此操作。作为第二个例子:

integer(kind=bigint) function pow(a,pwr)
    implicit none
    integer(kind=bigint), value :: a, pwr
    pow=1
    do while(cur>0)
        if(mod(pwr,2)==1)pow=mod(pow*a,m)
        a=MOD(a*a,m)
        pwr=pwr/2
    end do
end function

您现在甚至可以将pow标记为纯函数。

最后,如果使用value属性,则在引用该函数时需要显式接口可用。使用该功能的模块就是这种情况,但在更一般的情况下需要考虑这一点。