我正在尝试创建一个有用的函数库。我还不太了解这一点,但显然大部分,如果不是全部,都需要包含在一个模块中(或者在程序内部的接口中,但是由于这一点是要创建一个库,所以似乎是一个选择)或者我将使用它们的程序将无法识别它们。
我可以使用包含所有这些功能的一个模块制作一个长文件,但我想将不同的功能保存在不同的短文件中。但是,如果我这样做,我将不得不为每个函数创建一个不同的模块,如果我想在程序中使用它们,我会有一个很长的USE
声明列表(更不用说数字了) .mod文件将被生成)。
我能提出的唯一可能的解决方案是,为所有其他模块创建另一个只包含USE
声明的模块,但我认为必须有另一种方法来使包含函数的库不是那么遥远。
另外,为什么我有这个问题而不是子程序?是因为命令CALL
立即将该行标识为子程序调用,而函数只是通过名称调用,没有命令告诉编译器“嘿,这是一个函数”,所以它必须知道什么是函数什么不事先?
我提供了一个示例(按照http://www.oceanographers.net/forums/showthread.php?378-How-to-make-a-FORTRAN-library中的说明操作,并使用正确的“路径”)。
TestFunc.F90
FUNCTION SumNum(nNum1,nNum2) RESULT(nResult)
IMPLICIT NONE
INTEGER,INTENT(IN) :: nNum1,nNum2
INTEGER :: nResult
nResult=nNum1+nNum2
RETURN;END FUNCTION
TestProg.F90
PROGRAM TestProg
IMPLICIT NONE
WRITE(6,*) SumNum(2,2)
STOP;END PROGRAM
命令行
> gfortran -c TestFunc.F90 -o TestFunc.o
> ar ruv libmylib.a *.o
> gfortran TestProg.F90 -o Test.x -L/path -lmylib.a
TestProg.F90:6.12:
WRITE(6,*) SumNum(2,2)
1
Error: Function 'sumnum' at (1) has no IMPLICIT type
答案 0 :(得分:7)
我的建议是将您的函数和子例程放入一个模块中,然后使用该模块。将逻辑上相关的那些放在同一个模块中。每个程序使用一个模块似乎非常不方便 - 为什么你更喜欢这种方法?将过程(函数和子例程)放入模块然后“使用”该模块的原因是它使接口“显式”,以便编译器可以检查调用中的实际参数与过程的伪参数之间的一致性。这将找到许多类型的错误,并节省您的编程工作量。与编写声明(“接口”)相比,它简单易行。您不必编写过程声明和接口,并且在进行修订时不必保持它们的一致性。是的,“call”语句帮助编译器识别子程序,但通过模块使接口显式化的优点需要模块用于函数和子程序。
编辑回答评论:是的,即使将程序放入库中,我也将它们放入单个模块中。如果程序完全不相关,那么它们可能属于单独的库和单独的模块。如果相关,则在同一个库和相同的模块中。 Fortran通过在同一模块中提供许多过程来提供管理可能“问题”的功能:您可以在“use”语句中明确使用哪些过程,并通过使用“only”子句避免名称冲突,仅列出过程使用。如果默认名称与其他名称冲突,您甚至可以重命名要使用的过程。
答案 1 :(得分:4)
您不需要在模块中放置子程序来创建库。我通常做的是在单独的文件中创建子程序,从中创建目标文件(.o),然后将它们存档到库中,例如:
ar ruv mylib.a *.o
然后,只需在与调用子例程的主程序链接时指定mylib.a。无论您的程序是子程序还是函数,它都没有区别。
EDIT1: 您的主程序需要有一个函数声明:
PROGRAM TestProg
IMPLICIT NONE
INTEGER :: sumnum
WRITE(6,*) SumNum(2,2)
STOP;END PROGRAM
然后:
gfortran -c *.f90
ar ruv mylib.a testfunc.o
gfortran testprog.o -o x mylib.a
当我运行x时,我得到正确的输出。
答案 2 :(得分:0)
使用隐式接口回答有关函数和子例程之间差异的问题:函数与变量一样使用,并且需要知道类型,因此需要使用external属性声明它们。 但是,我也强烈建议M. S. B.的回答,你应该将所有内容放入模块中,通过这种方式,你可以获得所有例程的显式接口,并避免这些问题。还有一个注释,示例代码中的return语句以及stop。