Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/fortran/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Syntax Fortran用括号传递参数可防止更改_Syntax_Fortran_Parameter Passing_Pass By Reference_Brackets - Fatal编程技术网

Syntax Fortran用括号传递参数可防止更改

Syntax Fortran用括号传递参数可防止更改,syntax,fortran,parameter-passing,pass-by-reference,brackets,Syntax,Fortran,Parameter Passing,Pass By Reference,Brackets,在这篇文章中,我询问了一个显式阻止传递参数进行更改的方法。一个显而易见的解决方案是定义参数的副本,并在这些副本上操作算法。然而,在评论中,我指出了一个事实,即我可以调用函数并将我不想更改的参数包装在括号中。这与创建所传递变量的副本的效果相同,因此不会发生更改。但我不明白它是如何工作的,括号实际上在做什么。有人能给我解释一下吗 下面是一个简单的例子,其中的行为发生如我所描述的 1 program argTest

在这篇文章中,我询问了一个显式阻止传递参数进行更改的方法。一个显而易见的解决方案是定义参数的副本,并在这些副本上操作算法。然而,在评论中,我指出了一个事实,即我可以调用函数并将我不想更改的参数包装在括号中。这与创建所传递变量的副本的效果相同,因此不会发生更改。但我不明白它是如何工作的,括号实际上在做什么。有人能给我解释一下吗

下面是一个简单的例子,其中的行为发生如我所描述的

  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                                                              

我认为解释是这样的,尽管我不能指出标准中明确的一部分

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

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

(a) = some_value
查看编译器如何处理它们


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

使用(非标准)loc()函数打印实际参数和伪参数的地址,并对它们进行比较,可能会很有趣,例如:

program main
    implicit none
    integer :: a

    a = 5
    print *, "address(a) = ", loc( a )

    call sub( 100 * a )
    call sub( 1 * a   )
    call sub( 1 * (a) )
    call sub( (a)     )
    call sub( a       )
contains

subroutine sub( n )
    integer :: n
    n = n + 1
    print "(2(a,i4,3x),a,i18)", "a=", a, " n=", n, "address(n) =", loc( n )
end subroutine

end program
输出变成这样,这表明包含表达式结果的临时变量实际上被传递到
sub()
(最后一种情况除外)

(有趣的是,Oracle出于某种原因对
a
使用了一个非常小的地址……尽管其他编译器使用了非常类似的地址。)

[编辑]根据Ian的上述回答,为表达式(值=常量,而非变量)产生的内存赋值是非法的。因此,请将上述代码作为一种尝试,以确认(…)传递的内容与原始的
a
不同。语法
(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)

好的,这证明了它确实是另一个变量,我在子程序中操作它。地址值基本上是随机的。很大的差异可能是由于在堆或堆栈上分配了临时语句造成的。如果我尝试您建议的
(a)=a*100
,那么我的编译器(gfortran 5.4.0)会抱怨这是一条“不可分类语句”。如果我使用类似于“((a))”的东西,编译器会做什么。例如,如果我有一个非常大的数组,它占用了我内存的一半,那么
a
和它的一个副本只适合我的内存。
((a))
是否会导致内存不足错误?!?对于这个问题中的例子,相关部分实际上是5.3.10p5-“如果没有为伪参数指定意图属性,则其使用受其有效参数的限制”。此处与
a
伪参数对应的实际参数是一个非指针表达式
(a)
(R1223,R701)-作为执行第一个子例程引用的一部分,对该表达式进行求值(12.5.4,7.1.1p3),以给出一个作为关联有效参数的值。值是不可定义的,但问题中的代码就是这样,代码是不一致的,任何事情都可能发生。
real :: tmp_a
...
tmp_a = a
call change(tmp_a, b, c)