Fortran 传递带括号的参数可防止更改

v.t*_*ala 4 syntax fortran brackets parameter-passing pass-by-reference

在这个 问题中,我询问了一种明确防止传递的参数进行更改的方法。一个明显的解决方案是定义参数的副本并在这些副本上运行算法。但是,在评论中,我指出了一个事实,即我可以调用该函数并将我不想在括号中更改的参数包装起来。这与创建传递的变量的副本具有相同的效果,因此它不会更改。但我不明白它是如何工作的以及括号实际上在做什么。所以有人可以给我解释一下吗?

这是一个简单的示例,其中发生了我所描述的行为。

  1 program argTest                                                                 
  2   implicit none                                                                 
  3   real            ::  a, b, c                                                   
  4                                                                                 
  5   interface       !optional interface                                                              
  6     subroutine change(a,b,c)                                                    
  7       real           ::  a, b, c                                                
  8     end subroutine change                                                       
  9   end interface                                                                 
 10                                                                                 
 11   write(*,*) 'Input a,b,c: '                                                    
 12   read(*,*) a, b, c                                                             
 13                                                                                 
 14   write(*,*) 'Values at start:'                                                 
 15   write(*,*)'a:', a                                                             
 16   write(*,*)'b:', b                                                             
 17   write(*,*)'c:', c                                                             
 18                                                                                 
 19                                                                                 
 20   call change((a),b,c)                                                          
 21   write(*,*)'Values after calling change with brackets around a:'               
 22   write(*,*)'a:', a                                                             
 23   write(*,*)'b:', b                                                             
 24   write(*,*)'c:', c                                                             
 25                                                                                 
 26                                                                                 
 27   call change(a,b,c)                                                            
 28   write(*,*)'Values after calling change without brackets:'                     
 29   write(*,*)'a:', a                                                             
 30   write(*,*)'b:', b                                                             
 31   write(*,*)'c:', c                                                             
 32                                                                                 
 33 end program argTest                                                             
 34                                                                                 
 35                                                                                 
 36 subroutine change(a,b,c)                                                        
 37   real           ::  a, b, c                                                    
 38                                                                                 
 39   a = a*2                                                                       
 40   b = b*3                                                                       
 41   c = c*4                                                                       
 42                                                                                 
 43 end subroutine change                                                           
 44      
 45
 46                                                              
Run Code Online (Sandbox Code Playgroud)

Ian*_*anH 5

(a)在问题代码的上下文中,语法是一个表达式。在没有指针结果的情况下,对表达式求值以产生一个值。在这种情况下,表达式的值与变量的值相同a

虽然计算表达式的结果(a)和变量a具有相同的值,但它们不是一回事 - 变量的值与变量本身的概念不同。这用于某些情况下,需要将相同的变量作为输入参数和单独的输出参数提供,否则会违反 Fortran 对参数别名的限制。

然而- 如上所述 - 在没有指针结果的情况下,评估表达式的结果是一个值,而不是一个变量。 不允许重新定义值。从概念上讲,说“我将改变值的含义2”或“我将改变评估结果的含义”是没有意义的1 + 1

当您使用这样的表达式作为实际参数时,它不能与在过程中重新定义的虚拟参数相关联。

在子例程中change,与表达式的值关联的虚拟参数(a)被重新定义。这是不符合的。

是否制作副本是您不能(也不能)指望的实施细节 - 链接问题中的评论不准确。例如,知道上面讨论的这个限制的编译器知道子例程change实际上不能以符合的方式更改第一个参数,可能知道它对 不a可见change,因此决定它不需要制作临时副本的a用于表达的结果。

如果您需要制作某事物的临时副本,请编写制作副本的语句。

real :: tmp_a
...
tmp_a = a
call change(tmp_a, b, c)
Run Code Online (Sandbox Code Playgroud)


Hig*_*ark 4

我认为解释是这样的,尽管我无法指出标准中明确的部分,......

(a)是一个结果与 相同的表达式a。传递给子例程的是对该表达式求值的结果。Fortran 不允许对该结果进行赋值,就像传递cos(a)给子例程一样。我猜结果(a)几乎与副本完全相同a,这可能解释了令人费解的 OP 的行为。

我这台计算机上没有 Fortran,但如果有的话,我会尝试更多一些情况,其中 和 之间的差异a可能(a)很重要,例如

(a) = some_value
Run Code Online (Sandbox Code Playgroud)

看看编译器如何处理它们。

下面@IanH 的评论指出了语言标准的相关部分。