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