2012-11-01 15 views
1

我已經繼承了大約400行非常奇怪的Fortran 77代碼,我試圖逐步分析它,以便在我的腦海中清楚地說明它。Fortran'call'聲明:它實際上可以調用什麼?

無論如何,我有一個頭狀文件(實際上是一個.h,但在它的代碼是在FORTRAN不C/C++),在它只是兩個語句,稱爲getarg.h

character*80 serie 
integer ln 

然後我還有一個Fortran文件(.f)呼籲getserie.h它有這個代碼裏面:

subroutine getserie(serie, ln) 
include 'getarg.h' 
call getarg(1, serie) 
ln = index(serie, ' ') - 1 
return 
end 

我的問題的存在:我可以call與它只是變量聲明的外部文件?這樣做的效果是什麼?

回答

6

不,您只能調用子例程。這意味着指定爲subroutine的子程序。但是子程序的定義不一定要在你的源文件中。它只需要在鏈接時提供。

getarg子程序可能是您的編譯器的內部子程序,其中gets the command line arguments。這意味着編譯器自動向鏈接器提供子例程的代碼。

不以任何方式調用文件getarg.h。其內容僅直接複製到include聲明的位置。

在某些情況下,您需要調用子例程的(顯式)接口可用,但在後來的Fortran 90或更高版本中。在這些現代版本中,通常將子例程和函數放在模塊中,以便編譯器可以檢查您是否正確調用它們。

1

大多數FORTRAN 實現的一個特殊功能是CALL幾乎可以調用任何外部符號。當然,只有調用SUBROUTINE纔有意義。這可能是因爲衆所周知的FORTRAN調用約定 - 所有實際參數都是通過地址傳遞的,即所有實際傳遞給子例程的參數都是相同類型的 - 它們都是指針。即使是常數也通過地址傳遞 - 包含常量值的內存位置的地址。這允許編譯器生成對任何子例程的調用,而不需要提供顯式原型。它只是將所有參數指針推入堆棧(在基於堆棧的調用約定的平臺上),或者將它們加載到相應的寄存器中(在具有寄存器調用約定的平臺上),並將指令發送到符號的地址,用作子程序名稱在CALL聲明中。如果鏈接時存在這樣的符號,鏈接器將產生一個可執行文件,否則它會抱怨一個未解析的符號引用,並且不會生成可執行文件。

函數調用也是如此。編譯器用來通過數組索引操作告訴函數調用的唯一特性是(非內在的)函數聲明爲EXTERNAL。由於調用函數和訪問數組元素的語法是相同的,所以需要特殊的EXTERNAL指定。還有一些特殊的預定義函數,稱爲內部函數,它們在編譯器內部被識別(例如SIN)。也有內在的子程序,但其中大多數只是庫子程序。

所以每當你遇到一個CALL foo(...)聲明,你不知道什麼是foo,您應該諮詢你的編譯器的說明書,看是否內在這個名稱存在。如果沒有,它可能定義在代碼的某處 - 尋找SUBROUTINE foo。如果不是,它應該是從外部庫導出的子程序,鏈接到程序中,或者只是語法錯誤。

這一切都是非常容易出錯的,因爲人們可以很容易地提供與子程序所期望的完全不同類型的實際參數,或者甚至可以提供不同數量的實際參數,編譯器仍然會很高興地編譯代碼。當然,這樣的程序通常在運行時崩潰或產生無意義的結果。這就是爲什麼像flint這樣的特殊程序開發的目的是爲了檢查整個源代碼是否存在編譯器無法檢測到的問題(例如參數類型不匹配,實際參數數量錯誤等).Fortran 90通過引入接口來解決此問題。在某些情況下,接口是強制性的,但通常可用於提供編譯時參數檢查。

+0

這其實給我帶來一堆麻煩一次。我將幾個代碼連接在一起,代碼A有一個名爲'drift'的子例程。代碼B有一個名爲「漂移」的公共塊。當代碼A試圖調用'漂移'時,我得到了一些奇怪的錯誤(顯然它試圖調用公共塊)。 – mgilson

+0

聽起來很糟糕(太不嚴格?)連接器。通常這應該會產生符號重定義錯誤。或者至少有一個警告。 –

+0

我使用'gfortran',所以它是gcc的工作。但是,當我終於明白髮生了什麼時,我有些驚訝。 – mgilson

0

如上所述,這裏唯一不可思議的是包含文件名稱的可疑選擇。 (.h擴展名和內部符號名稱的不相關使用)。 (是的,我知道getarg不是標準的f77,而是一個擴展名)

將變量聲明放入包含文件是確保程序單元之間一致的聲明的通常做法。毫無疑問,該文件也被包含在調用程序中,並確保您的字符串在任何地方都以相同的長度聲明。

這就是說在這個例子中,它是絕對沒有必要的。你可以聲明字符串的假定長度,所以制定的包括:在主程序

character serie*(*) 
integer ln 

以及正常的聲明和擺脫包含文件混亂。

(現在有人會告訴我在不支持的假定長度字符串聲明瞭上世紀初的一些編譯器)..

相關問題