为什么Fortran代码会出现分段错误? [英] Why Fortran Code gets Segmentation Fault?
问题描述
下面的fortran代码出现分段错误.但是,当我将 print *,pow(10_8,i)
修改为 print *,pow(j,i)
时,它不会呕吐分段错误.为什么?这很奇怪.
The fortran code below gets segmentation faults.
However, when I modify print*,pow(10_8,i)
to print*,pow(j,i)
, it works without vomiting segmentation fault. Why? This is very weird.
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
推荐答案
这里的问题出在函数 pow
的自变量 a
上.在函数中,参数 a
(可能)在行上被修改了
The problem here is with the argument a
of the function pow
. In the function the argument a
is (potentially) modified on the line
a=MOD(a*a,m)
引用该函数时,实际参数 10_8
是文字常量,不能修改.这是您的程序失败时.当您使用 print *,pow(j,i)
时, j
是一个可以修改 的变量,并且程序不会失败
The actual argument 10_8
when referencing the function is a literal constant which may not be modified. This is when your program fails. When you use print*,pow(j,i)
the j
is a variable which may be modified, and your program doesn't fail.
这里发生了很多复杂的事情,在这个答案中我不会完全解释(您可以搜索有关此问题的其他信息).一个主题是 argument association (参数关联),该主题解释了为什么要尝试修改常量 10_8
.但是,我会说一些关于虚拟参数意图.
There is a lot of complicated stuff going on here, that I won't fully explain in this answer (you can search for other questions for that). One topic is argument association which explains why you are trying to modify the constant 10_8
. However, I'll say something about dummy argument intents.
伪参数 a
没有指定意图.当您打算使用 a
的值进入函数时,并且希望(可能)对其进行修改时,适当的意图应为 intent(inout)
.如果应用此方法,则应该发现编译器抱怨该分配行.
The dummy argument a
has no intent specified. As you intend to use the value of the a
as it enters the function and you wish to (potentially) modify it an appropriate intent would be intent(inout)
. If you apply this, you should find your compiler complain about that assignment line.
没有问题的意图是可以接受的.这具有某些含义.也就是说,是否可以修改 a
取决于在引用该函数时实际的参数是否可以修改.当实际的参数是 10_8
时,它可能不是.当它是 j
时.
Having no intent, such as in the case of the question, is an acceptible thing. This has certain meaning. That is, whether a
may be modified depends on whether the actual argument when referencing the function may. When the actual argument is 10_8
it may not; when it is j
it may.
至关重要的是,检查程序是否在此处应做的事情不是编译器的责任,而是您的责任.
The crucial thing is that it isn't the compiler's responsibility, but yours, to check whether the program is doing something here it shouldn't.
现在,即使允许,您可能也不想修改实际的参数 j
.您有两种选择:
Now, you may not want to modify the actual argument j
even when you are allowed to. You have a couple of options:
- 您可以制作一个临时的本地副本(并将
a
标记为intent(in)
),可以安全地对其进行修改; - 您可以使用
value
属性为输入数据创建匿名可修改的副本.
- you can make a temporary local copy (and mark
a
asintent(in)
), which may be safely modified; - you can make an anonymous modifiable copy of the input data using the
value
attribute.
您首先使用 cur = pwr
进行此操作.作为第二个示例:
You do this first with cur=pwr
. As an example of the second:
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
标记为纯函数.
You now may even mark pow
as a pure function.
最后,如果使用 value
属性,则在引用该函数时要求显式接口可用.使用此功能的模块就是这种情况,但是在更一般的情况下需要考虑这一点.
Finally, if using the value
attribute it is required that an explicit interface be available when referencing the function. With the module for the function this is the case here, but this is something to consider in more general cases.
这篇关于为什么Fortran代码会出现分段错误?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!