【Fortran】过程设计之一(子例程SUBROUTINE)
目錄
- 前言
- Fortran子例程(SUBROUTINE)
- 1) 使用方式
- 2) 子例程示意
- 3) INTENT屬性
- 4) 傳遞數組給子例程
- 4) 傳遞可分配數組給子例程
- 5) 傳遞字符變量給子例程
- 6) 子例程作為參數傳遞
- 7) 其它注意事項
前言
程序單元包括主程序、子例程、模塊、函數子程序。
在Fortran中,大型程序可以拆分成多個獨立運行和調試的子任務,即程序單元(亦稱為外部過程)。
Fortran中有兩種外部過程:子例程和函數子程序。這種機制的優點是:
- 子任務單獨測試,相互之間不影響;
- 避免重復造輪子,調用即可;
- 將實現某一功能的代碼封裝起來,避免不經意修改導致代碼錯誤而不自知。
Fortran子例程(SUBROUTINE)
1) 使用方式
子例程(亦可稱為子程序)是一個Fortran過程,通過CALL語句進行調用,并通過參數表獲取輸入數值和返回結果。
定義語句格式:
注意事項:
- subroutine_name由字母、數字和下劃線組成 ,最大長度可達63個字符,第一個字符為字母;
- argument_list_dum,形參,一系列變量和/或數組,從調用程序傳遞給子例程;
- 子例程是一個獨立的程序單元,開始于SUBROUTINE,結束于END SUBROUTINE,其中的局部變量名和語句標號(“行號”)可以在其它地方復用(不用擔心重名);
- 實際上沒有給形參分配內存。
調用語句格式:
CALL subroutine_name( argument_list_act )
注意事項:
- 任何可執行程序單元都可以調用子例程,但不能調用自身(除非定義為遞歸類型);
- argument_list_act,實參。實參的個數、順序與類型必須和形參的個數、順序與類型相匹配。
- 主程序和子例程之間采用地址傳遞進行參數傳遞,具體過程是:由于主程序中的實參有具體的內存存儲位置,當調用子例程時,主程序將生成多個指針來指向各個實參所對應的存儲位置,并將指針傳遞給子例程,子例程調用的是參數的內存位置,而非實參數據本身。
2) 子例程示意
已知三角形的兩條直邊,計算斜邊。要求計算過程用子例程,主程序直接輸入相應數據后直接調用。
PROGRAM calc_hypotenuse_test ! 主程序 IMPLICIT NONE REAL :: s1 REAL :: s2 REAL :: hypotWRITE(*,*) '測試計算斜邊的子例程' WRITE(*,*)'輸入第一條直邊的長度:' READ(*,*) s1 WRITE(*,*)'輸入第二條直邊的長度:' READ(*,*) s2CALL calc_hypotenuse( s1, s2 , hypot ) ! 調用子例程WRITE( *, 100 ) hypot 100 FORMAT('斜邊長度為:' , F10.4)STOP END PROGRAM calc_hypotenuse_test SUBROUTINE calc_hypotenuse(side_1 , side_2 , hypotenuse) ! 子例程 IMPLICIT NONE REAL , INTENT(IN)::side_1 ! 第一條直邊長度,輸入,INTENT用法見下述 REAL , INTENT(IN)::side_2 ! 第二條直邊長度,輸入 REAL , INTENT(OUT)::hypotenuse ! 斜邊長度,輸出REAL::temp ! 聲明局部變量 temp = side_1**2 + side_2**2 hypotenuse = SQRT( temp ) END SUBROUTINE calc_hypotenuse3) INTENT屬性
INTENT屬性在子例程的形參聲明時使用。
INTENT屬性的格式如下:
- INTENT(IN),形參僅用于向子程序傳遞輸入數據;
- INTENT(OUT),形參僅用于將結果返回給調用程序;
- INTENT(INOUT) 或 INTENT(IN OUT),形參既用來向子程序輸入數據,也用來向調用程序返回結果。
屬性特點:
- 對于每一個形參來說,都應該聲明一個合適的INTENT屬性;
- INTENT屬性僅對過程的形參有效,如果用來聲明子例程的局部變量或主程序的變量則會出錯;
- 對于每一個過程,都應該聲明每一個形參的INTENT屬性。形參的INTENT屬性也可以用獨立的語句來聲明,如:INTENT(IN) :: arg1 , arg2,...。
4) 傳遞數組給子例程
如前所述,調用參數實際上是通過傳遞指向該實參的內存位置指針來傳遞給子例程。對于實參是一個數組,其指針是指向數組中的第一個值。然而,子例程需要同時知道數組的地址和大小,保證不會發生越界,才能進行數組操作。
在子例程中有三種方式來指明形參數組的大小:
顯式結構形參數組
數組的維度大小需要作為參數進行傳遞,一維數組為例:
二維數組為例:
SUBROUTINE process1(data1 , data2 , m , n) INTEGER , INTENT(IN) :: m ,n ! m×n為數組的大小 REAL , INTENT(IN) , DIMENSION(m,n)::data1 REAL , INTENT(OUT) , DIMENSION(m,n)::data2 data2 = 3.*data1 ! 將data1數組的數值乘以3,賦值為data2數組,直接對數組進行操作END SUBROUTINE process1由于形參數組的大小和結構都已經清晰,可以對形參數組進行數組操作,以及切片操作。
不定結構形參數組
把子例程中的所有形參數組聲明為不定結構(數組的每個下標用:來代替)的形參數組,只有當子例程具有顯式接口時,才能使用這種數組。因此,顯示接口能夠給編譯器提供每個數組的大小、結構等詳細信息,在調用的時候不會出錯。
需注意的是,定義形參數組時只有它的結構(但用:替代),沒有具體下標范圍。因此,在把實參數組傳遞至形參數組時,只傳遞了結構,并沒有傳遞實參數組每個維度的下標取值范圍。此時,可以用查詢函數獲取不定結構數組的結構。
如果不需要將數組的每個維度下標邊界從調用程序傳遞給子例程,則不定結構形參數組比顯式結構形參數組更方便使用。 二維數組的例子:
MODULE module_process CONTAINSSUBROUTINE process2(data1 , data2 )REAL , INTENT(IN) , DIMENSION(:,:)::data1 REAL , INTENT(OUT) , DIMENSION(:,:)::data2 data2 = 3.*data1 ! 將data1數組的數值乘以3,賦值為data2數組,直接對數組進行操作END SUBROUTINE process2 END MODULE module_process不定大小形參數組
古老且過時的方法,用星號*來聲明形參數組的長度,表示大小不確定。因此不清楚數組的實際大小和結構,容易運行錯誤,且很難調試,建議不要使用。例子如下:
4) 傳遞可分配數組給子例程
可分配數組作為參數傳遞給子例程時,必須要結合顯式接口。
注意事項:
-
當傳遞的參數是可分配數組時,子例程中形參聲明 和 調用子程序的實參聲明必須都是可分配的;
-
可分配形參可以使用INTENT屬性,但INTENT屬性的具體參數可能會影響子例程中的操作:
- INTENT(IN),在子例程中不允許對輸入可分配數組進行重分配或者釋放內存空間;
- INTENT(INOUT),調用子例程時,如果參數只有數組這一個,那么實際上會將數組的狀態(是否可分配)和相應數據傳遞至子例程中(實參——>形參),在子例程中可以對形參修改、釋放內存、重分配等操作。形參的最終狀態和數據返回至調用程序中(相應實參結果被修改了)。具體見下例;
- INTENT(OUT),調用子例程時,實參在入口處被自動釋放掉,相應的數據清除掉,可以在子例程中對其進行操作,然后將形參的最終狀態和數據返回至調用程序中。
例子:
取自《Fortran for Scientists and Engineers(4th) by Stephen J. Chapman》中的9-5例題,有少量修改,復制可運行。
相應的結果為:
調用子程序前主程序中的數組: 1.0 2.0 3.0 4.0 5.0 6.0 子程序分配成功! 子程序輸入為: 1.0 2.0 3.0 4.0 5.0 6.0 子程序中輸出的數組 5.0 4.0 3.0 2.0 1.0 調用子程序后主程序中的數組: 5.0 4.0 3.0 2.0 1.05) 傳遞字符變量給子例程
當一個字符變量被作為子例程的形參時,用*號來聲明字符變量的長度。當調用子例程時,形參的長度將是實參的長度。如:
SUBROUTINE example( string ) CHARACTER( len = * ) , INTENT(IN) :: string ! *號表示完全復制實參的長度 WRITE(*,*) 'The lengrh of string : ',LEN(string) ! 可以在子例程內部實時返回實參的長度 END SUBROUTINE example如自動數組一般,創建自動字符變量:
SUBROUTINE sample ( string ) CHARACTER(len=*) :: string CHARACTER(len=len(string)) :: temp ! 一個與形參相同大小的臨時變量,子例程調用結束時會被銷毀6) 子例程作為參數傳遞
當子例程a作為實參時,傳遞給過程A(如另一子例程)一個指向該子例程a的指針。執行該過程A時,參數表中的子例程a將作為形參進入到過程A的編譯當中。
要想實現子例程傳遞功能,必須要使用EXTERNAL屬性,將子例程聲明為外部,此時編譯器才會知道參數表中傳遞的是獨立的已編譯子例程,而不是常規變量。
EXTERNAL屬性需要在聲明部分中使用,格式如下:
TYPE, EXTERNAL ::sub_1 , sub_2 ! TYPE是指具體數據類型或者
EXTERNAL ::sub_1 , sub_2同時,在過程中需要結合CALL語句,以調用過程中子例程形參。
7) 其它注意事項
- 不要在子例程中使用STOP語句,因為一旦調用子例程時,會停止程序。如果調用多個子例程(每個子例程都有STOP語句),則程序永遠不會執行成功;
- 如果子例程中存在可能引發錯誤的條件,應該對錯誤進行檢測,并設置正確/錯誤標志,返回給調用程序(即作為形參其中之一),用于實時判斷預設條件的執行成功與否(即可定義為一種狀態用于判斷)。
總結
以上是生活随笔為你收集整理的【Fortran】过程设计之一(子例程SUBROUTINE)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 边缘计算网关 5G/4G物联网工业互联
- 下一篇: dya61