Fortran 中可以将子例程包含在子例程中(而不是在程序中)吗?
Can a subroutine be contained in a subroutine (not in a program) in Fortran?
我不得不处理一个用 Fortran 编写的旧软件(主要是在 70 年代编写的,并且维护不善到 3 年前)。
我正在尝试使用 VS2017 和 Intel oneAPI 编译器 (Fortran Compiler Classic 2021.3.0) 为 64 位架构编译它。
在更新其中一个模块的过程中,我说服自己编译器不支持我了解到的子例程之间所谓的“主机关联”(通过 CONTAINS 语句)。 None 在包含的子例程中定义的符号似乎在包含的子例程中可见(如果我在包含的子例程中使用 IMPLICIT NONE 编译器告诉我我需要声明所有它们,而如果我不要,编译器得到的声明非常错误,并且与包含的子例程中的声明不匹配。打印了很多误导性的错误消息。
你们中有人可以确认是这种情况,还是可以提供编译器选项来启用某些编译器过去明确允许的此功能?如果需要,我将 post 源代码(我不会立即 post 下载它,因为我认为这对于 Fortran 专家来说可能是一个非常幼稚的问题,而我是一个完全的新手)。
此致,
这里我根据评论中的要求补充原文POST
原代码:
Subroutine LoadUserLibs(TypesInDeck,*)
... OMITTED COMMENTS ...
! This routine is only used in the multi-DLL configuration (otherwise empty routine)
!dec$ if defined (TRNSYS_MULTI_DLL)
Use DFWIN
Use DFLIB
!Use KERNEL32
Use TrnsysConstants
Use TrnsysFunctions
Use TrnsysData, Only: steamMethod,isNISTSteamFound
! Force explicit variable declaration
Implicit None
! Local variable declarations
Type(T_WIN32_FIND_DATA):: WFD
Character (len=maxPathLength) UserDir,FoundListStr,SearchListStr
Character (len=maxMessageLength) msgString
Integer :: libFile, j, k
Logical :: bSt
Character (len=12) jStr,TypeNum,numDLLsStr
Character (len=20) routineName
Integer luw !listing file logical unit number
Integer (kind=8) ExistTest !declares an integer to temporarily contain a pointer
Integer i !not used but must be delcared as part of a POINTER declaration.
Integer (kind=8) LibHandles(100) !declares an array where handles to loaded libraries are stored.
Integer LibCount !a counter variable used to keep track of how many dlls have been loaded
Integer TypeCount !a counter variable used to count how many Types were found in a given dll.
Integer TypesInDeck(nMaxUnits) !an array containing a list of Types that are in the deck being run.
Integer TotalTypes/0/ !the total number of Types in the deck being run (no duplicates)
Integer TypesListed/0/ !a variable used to count how many of the Types that were found, have been listed so far.
Integer, Allocatable :: SearchList(:,:) !an array of Type numbers to look for in dlls.
Integer, Allocatable :: FoundList(:)
Logical :: isType155InDeck = .false., isType155DllFound = .false.
! Common black definitions
Integer(INT_PTR_KIND()) paa(nMaxTypes) !declares an integer array that will contain pointer addresses to the Types
Integer(INT_PTR_KIND()) saa !declares an integer that will contain a pointer address of the NIST steam routines.
Common /USRDLLS/ paa,saa
! Pointer definitions
Pointer (p,i)
... OMITTED CODE ...
!dec$ else
! Single-DLL configuration: empty routine
!dec$ endif
Return
Contains
Subroutine LoadTypesFromDll()
... OMITTED CODE ...
End Subroutine LoadTypesFromDll
End Subroutine LoadUserLibs
我在编译原始代码时收到的错误:
Severity Code Description Project File Line Suppression State
Error error #6303: The assignment operation or the binary expression operation is invalid for the data types of the two operands. C:\Development\trndll-vs2017-ifc\TRNDLL\SourceCode\Kernel\Userlib.f90 276
Error error #6303: The assignment operation or the binary expression operation is invalid for the data types of the two operands. C:\Development\trndll-vs2017-ifc\TRNDLL\SourceCode\Kernel\Userlib.f90 284
Error error #6303: The assignment operation or the binary expression operation is invalid for the data types of the two operands. C:\Development\trndll-vs2017-ifc\TRNDLL\SourceCode\Kernel\Userlib.f90 303
Error error #6303: The assignment operation or the binary expression operation is invalid for the data types of the two operands. C:\Development\trndll-vs2017-ifc\TRNDLL\SourceCode\Kernel\Userlib.f90 309
Error error #6303: The assignment operation or the binary expression operation is invalid for the data types of the two operands. C:\Development\trndll-vs2017-ifc\TRNDLL\SourceCode\Kernel\Userlib.f90 314
Error error #6303: The assignment operation or the binary expression operation is invalid for the data types of the two operands. C:\Development\trndll-vs2017-ifc\TRNDLL\SourceCode\Kernel\Userlib.f90 315
Error error #6303: The assignment operation or the binary expression operation is invalid for the data types of the two operands. C:\Development\trndll-vs2017-ifc\TRNDLL\SourceCode\Kernel\Userlib.f90 317
Error error #6303: The assignment operation or the binary expression operation is invalid for the data types of the two operands. [CFILENAME] C:\Development\trndll-vs2017-ifc\TRNDLL\SourceCode\Kernel\Userlib.f90 302
Error error #6303: The assignment operation or the binary expression operation is invalid for the data types of the two operands. [CFILENAME] C:\Development\trndll-vs2017-ifc\TRNDLL\SourceCode\Kernel\Userlib.f90 308
Error error #6362: The data types of the argument(s) are invalid. [TRIM] C:\Development\trndll-vs2017-ifc\TRNDLL\SourceCode\Kernel\Userlib.f90 276
Error error #6362: The data types of the argument(s) are invalid. [TRIM] C:\Development\trndll-vs2017-ifc\TRNDLL\SourceCode\Kernel\Userlib.f90 284
Error error #6362: The data types of the argument(s) are invalid. [TRIM] C:\Development\trndll-vs2017-ifc\TRNDLL\SourceCode\Kernel\Userlib.f90 284
Error error #6362: The data types of the argument(s) are invalid. [TRIM] C:\Development\trndll-vs2017-ifc\TRNDLL\SourceCode\Kernel\Userlib.f90 303
Error error #6362: The data types of the argument(s) are invalid. [TRIM] C:\Development\trndll-vs2017-ifc\TRNDLL\SourceCode\Kernel\Userlib.f90 309
Error error #6362: The data types of the argument(s) are invalid. [TRIM] C:\Development\trndll-vs2017-ifc\TRNDLL\SourceCode\Kernel\Userlib.f90 314
Error error #6362: The data types of the argument(s) are invalid. [TRIM] C:\Development\trndll-vs2017-ifc\TRNDLL\SourceCode\Kernel\Userlib.f90 315
Error error #6362: The data types of the argument(s) are invalid. [TRIM] C:\Development\trndll-vs2017-ifc\TRNDLL\SourceCode\Kernel\Userlib.f90 315
Error error #6362: The data types of the argument(s) are invalid. [TRIM] C:\Development\trndll-vs2017-ifc\TRNDLL\SourceCode\Kernel\Userlib.f90 317
Error error #6410: This name has not been declared as an array or a function. [FOUNDLIST] C:\Development\trndll-vs2017-ifc\TRNDLL\SourceCode\Kernel\Userlib.f90 291
Error error #6410: This name has not been declared as an array or a function. [LIBHANDLES] C:\Development\trndll-vs2017-ifc\TRNDLL\SourceCode\Kernel\Userlib.f90 268
Error error #6423: This name has already been used as an external function name. [PAA] C:\Development\trndll-vs2017-ifc\TRNDLL\SourceCode\Kernel\Userlib.f90 289
Error error #6423: This name has already been used as an external function name. [SEARCHLIST] C:\Development\trndll-vs2017-ifc\TRNDLL\SourceCode\Kernel\Userlib.f90 292
Error error #6460: This is not a component name that is defined in the encompassing structure. [CFILENAME] C:\Development\trndll-vs2017-ifc\TRNDLL\SourceCode\Kernel\Userlib.f90 283
Error error #6514: Substring or array slice notation requires CHARACTER type or array. [CFILENAME] C:\Development\trndll-vs2017-ifc\TRNDLL\SourceCode\Kernel\Userlib.f90 302
Error error #6514: Substring or array slice notation requires CHARACTER type or array. [CFILENAME] C:\Development\trndll-vs2017-ifc\TRNDLL\SourceCode\Kernel\Userlib.f90 308
Error error #6514: Substring or array slice notation requires CHARACTER type or array. [FOUNDLIST] C:\Development\trndll-vs2017-ifc\TRNDLL\SourceCode\Kernel\Userlib.f90 321
Error error #6514: Substring or array slice notation requires CHARACTER type or array. [TYPENUM] C:\Development\trndll-vs2017-ifc\TRNDLL\SourceCode\Kernel\Userlib.f90 284
Error error #6515: This function, which is specified as the left side of an assignment statement, is invalid. [PAA] C:\Development\trndll-vs2017-ifc\TRNDLL\SourceCode\Kernel\Userlib.f90 289
Error error #6515: This function, which is specified as the left side of an assignment statement, is invalid. [SEARCHLIST] C:\Development\trndll-vs2017-ifc\TRNDLL\SourceCode\Kernel\Userlib.f90 292
Error error #6535: This variable or component must be of a derived or structure type. [WFD] C:\Development\trndll-vs2017-ifc\TRNDLL\SourceCode\Kernel\Userlib.f90 283
内部程序(在CONTAINS
之后)可以看到在“宿主范围”(CONTAINS
之前)声明的所有实体,并且可以看到其他内部程序,但不能看到声明在其中的实体其他内部程序。主机关联仅上升到树。例如:
subroutine outer
integer :: X
...
contains
subroutine innerA
real :: A
end subroutine innerA
subroutine innerB
real :: B
end subroutine innerB
end subroutine outer
子例程 outer
可以看到 innerA
和 innerB
的显式接口。 innerA
和 innerB
可以看到彼此和变量 X
的显式接口,但是 innerA
看不到 innerB
的变量 B
和 innerB
看不到 innerA
的变量 A
.
我怀疑其他编译器是否支持您描述的行为。鉴于您说它是在 70 年代编写的,它不可能使用从 Fortran 90 开始的模块。我的猜测是您的“更新其中一个模块”引入了错误。
为了谁会设置 VS2017 + oneAPI 项目来构建 TRNSYS 内核,我 post 在这里解决问题,这与不同版本之间的 Fortran 语言不兼容无关。相反,这是由于未定义的宏 (TRNSYS_MULTI_DLL) 以及上述代码中对该宏的草率使用。
从上面源码中的注释可以看出,作者的意图是在没有定义那个宏的时候提供一个空函数。但是,由于被包含函数放在条件编译宏!dec$ endif
的末尾之后,这导致即使包含函数为空,被包含函数也存在。因此编译器抱怨实际上不再存在的符号。
在我看来,更好的做法是将包含的函数移动到条件编译宏中,如下所示。
Subroutine LoadUserLibs(TypesInDeck,*)
... OMITTED COMMENTS ...
!dec$ if defined (TRNSYS_MULTI_DLL)
! This routine is only used in the multi-DLL configuration (otherwise empty routine)
... OMITTED CODE ...
Return
Contains
Subroutine LoadTypesFromDll()
... OMITTED CODE ...
Return
End Subroutine LoadTypesFromDll
!dec$ else
! Single-DLL configuration: empty routine
Return
!dec$ endif
End Subroutine LoadUserLibs
我不得不处理一个用 Fortran 编写的旧软件(主要是在 70 年代编写的,并且维护不善到 3 年前)。
我正在尝试使用 VS2017 和 Intel oneAPI 编译器 (Fortran Compiler Classic 2021.3.0) 为 64 位架构编译它。
在更新其中一个模块的过程中,我说服自己编译器不支持我了解到的子例程之间所谓的“主机关联”(通过 CONTAINS 语句)。 None 在包含的子例程中定义的符号似乎在包含的子例程中可见(如果我在包含的子例程中使用 IMPLICIT NONE 编译器告诉我我需要声明所有它们,而如果我不要,编译器得到的声明非常错误,并且与包含的子例程中的声明不匹配。打印了很多误导性的错误消息。
你们中有人可以确认是这种情况,还是可以提供编译器选项来启用某些编译器过去明确允许的此功能?如果需要,我将 post 源代码(我不会立即 post 下载它,因为我认为这对于 Fortran 专家来说可能是一个非常幼稚的问题,而我是一个完全的新手)。
此致,
这里我根据评论中的要求补充原文POST
原代码:
Subroutine LoadUserLibs(TypesInDeck,*)
... OMITTED COMMENTS ...
! This routine is only used in the multi-DLL configuration (otherwise empty routine)
!dec$ if defined (TRNSYS_MULTI_DLL)
Use DFWIN
Use DFLIB
!Use KERNEL32
Use TrnsysConstants
Use TrnsysFunctions
Use TrnsysData, Only: steamMethod,isNISTSteamFound
! Force explicit variable declaration
Implicit None
! Local variable declarations
Type(T_WIN32_FIND_DATA):: WFD
Character (len=maxPathLength) UserDir,FoundListStr,SearchListStr
Character (len=maxMessageLength) msgString
Integer :: libFile, j, k
Logical :: bSt
Character (len=12) jStr,TypeNum,numDLLsStr
Character (len=20) routineName
Integer luw !listing file logical unit number
Integer (kind=8) ExistTest !declares an integer to temporarily contain a pointer
Integer i !not used but must be delcared as part of a POINTER declaration.
Integer (kind=8) LibHandles(100) !declares an array where handles to loaded libraries are stored.
Integer LibCount !a counter variable used to keep track of how many dlls have been loaded
Integer TypeCount !a counter variable used to count how many Types were found in a given dll.
Integer TypesInDeck(nMaxUnits) !an array containing a list of Types that are in the deck being run.
Integer TotalTypes/0/ !the total number of Types in the deck being run (no duplicates)
Integer TypesListed/0/ !a variable used to count how many of the Types that were found, have been listed so far.
Integer, Allocatable :: SearchList(:,:) !an array of Type numbers to look for in dlls.
Integer, Allocatable :: FoundList(:)
Logical :: isType155InDeck = .false., isType155DllFound = .false.
! Common black definitions
Integer(INT_PTR_KIND()) paa(nMaxTypes) !declares an integer array that will contain pointer addresses to the Types
Integer(INT_PTR_KIND()) saa !declares an integer that will contain a pointer address of the NIST steam routines.
Common /USRDLLS/ paa,saa
! Pointer definitions
Pointer (p,i)
... OMITTED CODE ...
!dec$ else
! Single-DLL configuration: empty routine
!dec$ endif
Return
Contains
Subroutine LoadTypesFromDll()
... OMITTED CODE ...
End Subroutine LoadTypesFromDll
End Subroutine LoadUserLibs
我在编译原始代码时收到的错误:
Severity Code Description Project File Line Suppression State
Error error #6303: The assignment operation or the binary expression operation is invalid for the data types of the two operands. C:\Development\trndll-vs2017-ifc\TRNDLL\SourceCode\Kernel\Userlib.f90 276
Error error #6303: The assignment operation or the binary expression operation is invalid for the data types of the two operands. C:\Development\trndll-vs2017-ifc\TRNDLL\SourceCode\Kernel\Userlib.f90 284
Error error #6303: The assignment operation or the binary expression operation is invalid for the data types of the two operands. C:\Development\trndll-vs2017-ifc\TRNDLL\SourceCode\Kernel\Userlib.f90 303
Error error #6303: The assignment operation or the binary expression operation is invalid for the data types of the two operands. C:\Development\trndll-vs2017-ifc\TRNDLL\SourceCode\Kernel\Userlib.f90 309
Error error #6303: The assignment operation or the binary expression operation is invalid for the data types of the two operands. C:\Development\trndll-vs2017-ifc\TRNDLL\SourceCode\Kernel\Userlib.f90 314
Error error #6303: The assignment operation or the binary expression operation is invalid for the data types of the two operands. C:\Development\trndll-vs2017-ifc\TRNDLL\SourceCode\Kernel\Userlib.f90 315
Error error #6303: The assignment operation or the binary expression operation is invalid for the data types of the two operands. C:\Development\trndll-vs2017-ifc\TRNDLL\SourceCode\Kernel\Userlib.f90 317
Error error #6303: The assignment operation or the binary expression operation is invalid for the data types of the two operands. [CFILENAME] C:\Development\trndll-vs2017-ifc\TRNDLL\SourceCode\Kernel\Userlib.f90 302
Error error #6303: The assignment operation or the binary expression operation is invalid for the data types of the two operands. [CFILENAME] C:\Development\trndll-vs2017-ifc\TRNDLL\SourceCode\Kernel\Userlib.f90 308
Error error #6362: The data types of the argument(s) are invalid. [TRIM] C:\Development\trndll-vs2017-ifc\TRNDLL\SourceCode\Kernel\Userlib.f90 276
Error error #6362: The data types of the argument(s) are invalid. [TRIM] C:\Development\trndll-vs2017-ifc\TRNDLL\SourceCode\Kernel\Userlib.f90 284
Error error #6362: The data types of the argument(s) are invalid. [TRIM] C:\Development\trndll-vs2017-ifc\TRNDLL\SourceCode\Kernel\Userlib.f90 284
Error error #6362: The data types of the argument(s) are invalid. [TRIM] C:\Development\trndll-vs2017-ifc\TRNDLL\SourceCode\Kernel\Userlib.f90 303
Error error #6362: The data types of the argument(s) are invalid. [TRIM] C:\Development\trndll-vs2017-ifc\TRNDLL\SourceCode\Kernel\Userlib.f90 309
Error error #6362: The data types of the argument(s) are invalid. [TRIM] C:\Development\trndll-vs2017-ifc\TRNDLL\SourceCode\Kernel\Userlib.f90 314
Error error #6362: The data types of the argument(s) are invalid. [TRIM] C:\Development\trndll-vs2017-ifc\TRNDLL\SourceCode\Kernel\Userlib.f90 315
Error error #6362: The data types of the argument(s) are invalid. [TRIM] C:\Development\trndll-vs2017-ifc\TRNDLL\SourceCode\Kernel\Userlib.f90 315
Error error #6362: The data types of the argument(s) are invalid. [TRIM] C:\Development\trndll-vs2017-ifc\TRNDLL\SourceCode\Kernel\Userlib.f90 317
Error error #6410: This name has not been declared as an array or a function. [FOUNDLIST] C:\Development\trndll-vs2017-ifc\TRNDLL\SourceCode\Kernel\Userlib.f90 291
Error error #6410: This name has not been declared as an array or a function. [LIBHANDLES] C:\Development\trndll-vs2017-ifc\TRNDLL\SourceCode\Kernel\Userlib.f90 268
Error error #6423: This name has already been used as an external function name. [PAA] C:\Development\trndll-vs2017-ifc\TRNDLL\SourceCode\Kernel\Userlib.f90 289
Error error #6423: This name has already been used as an external function name. [SEARCHLIST] C:\Development\trndll-vs2017-ifc\TRNDLL\SourceCode\Kernel\Userlib.f90 292
Error error #6460: This is not a component name that is defined in the encompassing structure. [CFILENAME] C:\Development\trndll-vs2017-ifc\TRNDLL\SourceCode\Kernel\Userlib.f90 283
Error error #6514: Substring or array slice notation requires CHARACTER type or array. [CFILENAME] C:\Development\trndll-vs2017-ifc\TRNDLL\SourceCode\Kernel\Userlib.f90 302
Error error #6514: Substring or array slice notation requires CHARACTER type or array. [CFILENAME] C:\Development\trndll-vs2017-ifc\TRNDLL\SourceCode\Kernel\Userlib.f90 308
Error error #6514: Substring or array slice notation requires CHARACTER type or array. [FOUNDLIST] C:\Development\trndll-vs2017-ifc\TRNDLL\SourceCode\Kernel\Userlib.f90 321
Error error #6514: Substring or array slice notation requires CHARACTER type or array. [TYPENUM] C:\Development\trndll-vs2017-ifc\TRNDLL\SourceCode\Kernel\Userlib.f90 284
Error error #6515: This function, which is specified as the left side of an assignment statement, is invalid. [PAA] C:\Development\trndll-vs2017-ifc\TRNDLL\SourceCode\Kernel\Userlib.f90 289
Error error #6515: This function, which is specified as the left side of an assignment statement, is invalid. [SEARCHLIST] C:\Development\trndll-vs2017-ifc\TRNDLL\SourceCode\Kernel\Userlib.f90 292
Error error #6535: This variable or component must be of a derived or structure type. [WFD] C:\Development\trndll-vs2017-ifc\TRNDLL\SourceCode\Kernel\Userlib.f90 283
内部程序(在CONTAINS
之后)可以看到在“宿主范围”(CONTAINS
之前)声明的所有实体,并且可以看到其他内部程序,但不能看到声明在其中的实体其他内部程序。主机关联仅上升到树。例如:
subroutine outer
integer :: X
...
contains
subroutine innerA
real :: A
end subroutine innerA
subroutine innerB
real :: B
end subroutine innerB
end subroutine outer
子例程 outer
可以看到 innerA
和 innerB
的显式接口。 innerA
和 innerB
可以看到彼此和变量 X
的显式接口,但是 innerA
看不到 innerB
的变量 B
和 innerB
看不到 innerA
的变量 A
.
我怀疑其他编译器是否支持您描述的行为。鉴于您说它是在 70 年代编写的,它不可能使用从 Fortran 90 开始的模块。我的猜测是您的“更新其中一个模块”引入了错误。
为了谁会设置 VS2017 + oneAPI 项目来构建 TRNSYS 内核,我 post 在这里解决问题,这与不同版本之间的 Fortran 语言不兼容无关。相反,这是由于未定义的宏 (TRNSYS_MULTI_DLL) 以及上述代码中对该宏的草率使用。
从上面源码中的注释可以看出,作者的意图是在没有定义那个宏的时候提供一个空函数。但是,由于被包含函数放在条件编译宏!dec$ endif
的末尾之后,这导致即使包含函数为空,被包含函数也存在。因此编译器抱怨实际上不再存在的符号。
在我看来,更好的做法是将包含的函数移动到条件编译宏中,如下所示。
Subroutine LoadUserLibs(TypesInDeck,*)
... OMITTED COMMENTS ...
!dec$ if defined (TRNSYS_MULTI_DLL)
! This routine is only used in the multi-DLL configuration (otherwise empty routine)
... OMITTED CODE ...
Return
Contains
Subroutine LoadTypesFromDll()
... OMITTED CODE ...
Return
End Subroutine LoadTypesFromDll
!dec$ else
! Single-DLL configuration: empty routine
Return
!dec$ endif
End Subroutine LoadUserLibs