Fortran中INCLUDE和模块的区别 [英] Difference between INCLUDE and modules in Fortran

查看:20
本文介绍了Fortran中INCLUDE和模块的区别的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

使用带有 use 语句的模块或带有 include 语句的隔离文件之间的实际区别是什么?我的意思是,如果我有一个在整个程序中经常使用的子例程:何时或为什么我应该将它放在一个模块中,或者只是将它写在一个单独的文件中,然后将它包含在程序的所有其他部分中用过吗?

What are the practical differences between using modules with the use statement or isolated files with the include statement? I mean, if I have a subroutine that is used a lot throughout a program: when or why should I put it inside a module or just write it in a separate file and include it in every other part of the program where it needs to be used?

此外,将所有打算进入模块的子例程编写在单独的文件中并在模块内使用 include 是否是一种好习惯?特别是如果子程序中的代码很长,以便更好地组织代码(这样所有子程序都打包在 mod 中,但如果我必须编辑一个,我不需要通过代码迷宫).

Also, would it be good practice to write all subroutines intended to go in a module in separate files and use include inside the module? Specially if the code in the subroutines is long, so as to keep the code better organized (that way all subroutines are packed in the mod, but if I have to edit one I don't need to go though a maze of code).

推荐答案

两者之间的概念差异映射到非常显着的实际差异.

The conceptual differences between the two map through to very significant practical differences.

INCLUDE 行在源代码级别运行 - 它完成简单(愚蠢")的文本包含.在包含行中没有对文件名"(不需要它实际上是一个文件)的任何特殊处理器解释的情况下,完整的源代码可以很容易地由程序员手动拼接在一起并提供给编译器,没有什么区别- 在源的语义中如此.包含的源代码并没有孤立的真正解释 - 它的含义完全取决于引用包含源的包含行出现的上下文.

An INCLUDE line operates at the source level - it accomplishes simple ("dumb") text inclusion. In the absence of any special processor interpretation of the "filename" (no requirement for that actually to be a file) in the include line the complete source could quite easily be manually spliced together by the programmer and fed to the compiler with no difference what-so-ever in the semantics of the source. Included source has no real interpretation in isolation - its meaning is completely dependent on the context in which the include line that references the included source appears.

模块在程序的更高实体级别运行,即在编译器考虑源实际描述的事物的级别.一个模块可以独立于其下游用户进行编译,一旦编译完成,编译器就确切地知道该模块可以为程序提供什么.

Modules operate at the much higher entity level of the program, i.e. at the level where the compiler is considering the things that the source actually describes. A module can be compiled in isolation of its downstream users and once it has been compiled the compiler knows exactly what things the module can provide to the program.

通常,使用包含行的人希望做的是模块实际设计要做的事情.

Typically what someone using include lines is hoping to do is what modules were actually designed to do.

示例问题:

  • 因为实体声明可以分布在多个语句中,所以包含的源所描述的实体可能不是您所期望的.考虑包含以下来源:

  • Because entity declarations can be spread over multiple statements the entities described by included source might not be what you expect. Consider the following source to be included:

INTEGER :: i

孤立地看来,这将名称 i 声明为一个整数标量(或者可能是一个函数?谁知道呢!).现在考虑包括上述内容的以下范围:

In isolation it looks like this declares the name i as an integer scalar (or perhaps a function? Who knows!). Now consider the following scope that includes the above:

INCLUDE "source from above"
维度:: i(10,10)

i 现在是一个二阶数组!也许你想让它成为一个指针?一个可分配的?一个伪论证?也许这会导致错误,或者它是有效的来源!在混合中加入隐式输入,真正增加潜在的乐趣.

i is now a rank two array! Perhaps you want to make it a POINTER? An ALLOCATABLE? A dummy argument? Perhaps that results in an error, or perhaps it is valid source! Throw implicit typing into the mix to really compound the potential fun.

模块中定义的实体完全"由模块定义.特定于使用范围的属性可以更改(易失性、可访问性等),但基本实体保持不变.名称冲突会被明确指出,并且可以通过 USE 语句中的重命名子句轻松解决.

An entity defined in a module is "completely" defined by the module. Attributes that are specific to the scope of use can be changed (VOLATILE, accessibility, etc), but the fundamental entity remains the same. Name clashes are explicitly called out and can be easily worked around with a rename clause on the USE statement.

Fortran 对语句顺序有限制(规范语句必须在可执行语句之前,等等).包含的源也受这些限制的约束,同样在包含点的上下文中,而不是源定义的点.

Fortran has restrictions on statement ordering (specification statements must go before executable statements, etc.). Included source is also subject to those restrictions, again in the context of the point of inclusion, not the point of source definition.

将语句函数定义(规范部分)和赋值语句(可执行部分)之间的源歧义很好地混合在一起,以获得一些完全钝的错误消息,或者更糟糕的是,编译器会默默接受错误代码.

Mix well with source ambiguity between statement function definitions (specification part) and assignment statements (executable part) for some completely obtuse error messages or, worse, silent acceptance by the compiler of erroneous code.

对引用模块的 USE 语句出现的位置有要求,但实际模块程序单元的来源完全独立于其使用点.

There are requirements on where the USE statement that references a module appears, but the source for the actual module program unit is completely independent of its point of use.

想要在相关过程之间共享一些全局状态,并且您想使用包含?让我向您介绍常见的块和序列关联的相关底层概念...

Fancy having some global state to be shared across related procedures and you want to use include? Let me introduce you to common blocks and the associated underlying concept of sequence association...

序列关联是早期底层 Fortran 处理器实现的不幸流血,它容易出错、不灵活、反优化不合时宜.

Sequence association is a unfortunate bleed-through of early underlying Fortran processor implementation that is an error prone, inflexible, anti-optimisation anachronism.

模块变量使常见的块及其相关的邪恶完全没有必要.

Module variables make common blocks and their associated evils completely unnecessary.

如果您使用了包含行,那么请注意您实际上并未包含常用过程的源代码(您第一段中的建议只会导致编译器出现一堆语法错误).您通常要做的是包含描述过程的接口的源代码.对于任何非平凡过程,描述接口的源与过程的完整源不同——这意味着您现在需要维护同一事物的两个源表示.这是一个容易出错的维护负担.

If you were using include lines, then note that you don't actually include the source of a commonly used procedure (the suggestion in your first paragraph is just going to result in a morass of syntax errors from the compiler). What you would typically do is include source that describes the interface of the procedure. For any non-trivial procedure the source that describes the interface is different from the complete source of the procedure - implying that you now need to maintain two source representations of the same thing. This is an error prone maintenance burden.

如前所述 - 编译器自动获得模块过程的接口知识(编译器知识是显式"的,因为它实际上看到了过程的代码 - 因此术语显式接口").程序员无需再做任何事情.

As mentioned - the compilers automatically gains knowledge of the interface of a module procedure (the compiler knowledge is "explicit" because it actually saw the procedure's code - hence the term "explicit interface"). No need for the programmer to do anything more.

上述结果是根本不应该使用外部子程序除非有很好的相反理由(可能存在循环或过度广泛的依赖关系) - 基本出发点应该把所有东西放在一个模块或主程序中.

A consequence of the above is that external subprograms should not be used at all unless there are very good reasons to the contrary (perhaps the existence of circular or excessively extensive dependencies) - the basic starting point should be to put everything in a module or main program.

其他发帖人提到了模块的源代码组织优势 - 包括能够将相关过程和其他东西"分组到一个包中,并控制内部实现细节的可访问性.

Other posters have mentioned the source code organisation benefits of modules - including the ability to group related procedures and other "stuff" into the one package, with control over accessibility of internal implementation details.

我接受根据问题的第二段有效使用 INCLUDE 行 - 大型模块在尺寸上变得笨拙.F2008 通过子模块解决了这个问题,这也带来了许多其他好处.一旦它们得到广泛支持,就应该放弃包含行的解决方法.

I accept there is a valid use of INCLUDE lines as per the second paragraph of the question - where large modules become unwieldy in size. F2008 has addressed this with submodules, which also bring a number of other benefits. Once they become widely supported the include line work-around should be abandoned.

第二个有效用途是克服语言对通用编程技术(C++ 中提供的模板)的支持的缺乏——即,操作中涉及的对象类型可能会有所不同,但描述要做什么的标记序列对那些对象做的事情本质上是一样的.语言可能还需要十年左右的时间才能解决这个问题.

A second valid use is to overcome a lack of support by the language for generic programming techniques (what templates provide in C++) - i.e. where the types of objects involved in an operation may vary, but the token sequence that describes what to do on those objects is essentially the same. It might be another decade or so before the language sorts that out.

这篇关于Fortran中INCLUDE和模块的区别的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆