2012-11-01 18 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 

以及正常的声明和摆脱包含文件混乱。

(现在有人会告诉我在不支持的假定长度字符串声明了上世纪初的一些编译器)..

相关问题