2013-03-27 326 views
9

使用模块与use语句或单独的文件与include语句之间的实际区别是什么?我的意思是,如果我有一个在整个程序中使用很多的子程序:什么时候或为什么要把它放在一个模块中,或者写在一个单独的文件中,并将它包含在程序中需要的其他部分用过的?Fortran中INCLUDE和模块之间的区别

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

回答

16

两个地图之间的概念差异到非常显着的实际差异。

INCLUDE行在源代码级别运行 - 它实现简单(“哑”)文本包含。如果没有任何特殊的处理器对include文件中的“文件名”的解释(实际上并不需要文件),那么完整的源代码可以非常容易地由程序员手动拼接在一起并送入编译器,而没有区别永远在源的语义。包含的来源没有单独的真实解释 - 其含义完全取决于引用包含来源的包含行的上下文。

模块在程序高得多的实体级别运行,即在编译器正在考虑源实际描述的事物的级别。一个模块可以独立于下游用户进行编译,一旦编译完成,编译器就可以准确知道模块可以提供给程序的内容。

通常什么人使用包括线是希望做的是什么模块实际上是设计做。

示例问题:

  • 由于实体声明可以分布在多个语句通过包括源描述的实体可能不是你所期望的。考虑到包括以下来源:

    INTEGER :: i

    在隔离它看起来像这样声明的名称i为一个整数标量(或者一个功能谁知道呢?!)。现在考虑下面的范围,包括上面:

    INCLUDE "source from above"
    DIMENSION :: i(10,10)

    i现在是一个等级×2个阵列!也许你想让它成为一个指针?一个ALLOCATABLE?一个虚假的争论?也许这会导致错误,或者它可能是有效的来源!将隐式类型输入到混合中以真正复合潜在的乐趣。

    一个模块中定义的实体的是“完全”由模块限定。可以改变特定于使用范围的属性(VOLATILE,可访问性等),但基本实体保持不变。名称冲突被明确地调出,并且可以使用USE语句中的重命名子句轻松解决。

  • Fortran语言对语句排序的限制(规范语句必须可执行语句之前,等等)。包括的来源也受限于这些限制,在包含的范围内,不是来源定义点的范围内的

    充分混合与一些完全钝角错误消息语句函数定义(规范的部分)和赋值语句(可执行部分)之间源歧义或更糟的是,无声接受的错误代码的编译器。

    有在哪里出现引用模块USE语句的要求,但实际的模块程序单元的源完全独立于它的使用点的。

  • 有花式到跨相关程序共享一些全局状态和要使用包括哪些内容?让我向您介绍常见块以及相关联的序列关联概念...

    序列关联是早期底层Fortran处理器实现的不幸流血,这是一种容易出错,不灵活的反优化时间错误。

    模块变量使得公共块及其相关的弊病完全不必要的。

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

    如前所述 - 编译器自动获取一个模块程序的界面的知识(编译器的知识是“明确的”,因为它居然看到了程序的代码 - 因此称为“显式接口”)。程序员不需要做更多的事情。

    上述结果是,除非有很好的理由相反(可能存在循环或过度依赖),否则不应使用外部子程序- 基本的出发点应该是一切在模块或主程序中。

其他海报提及模块的源代码组织的好处 - 包括能够将相关的程序和其他“东西”到一包,有超过的内部实现细节可访问控制。

我接受有包括线按问题的第二段的有效使用 - 在大型模块的尺寸变得笨重。 F2008通过子模块解决了这个问题,这也带来了其他一些好处。一旦它们得到广泛支持,应该放弃包含线的解决方法。

第二个有效的用法是克服通用编程技术(C++提供了什么模板)缺乏支持 - 即操作涉及的对象类型可能会有所不同,但描述什么的令牌序列对这些对象做的事情本质上是一样的。在语言排序之前可能还需要十年左右的时间。

+0

因此,在不同文件中分离子例程,然后在模块中使用include,没有缺点,对吧?我从来没有听说过子模块。 – Nordico 2013-03-28 16:18:50

+1

我只会考虑如果我有非常大的源文件或作为传统源迁移的一部分。如果可能的话,我会首先考虑将模块分解成多个“子”模块,然后将这些模块与USE语句在父模块中汇总在一起。但是,对于复杂的类型/过程依赖关系和/或Fortran的PUBLIC/PRIVATE辅助功能的工作方式,使用子模块可能并不总是可行。您可能会发现,将模块的源与INCLUDE行拼接在一起会混淆一些构建系统。 – IanH 2013-03-28 19:08:01

6

将过程放入模块并使用这些模块使过程的接口显式化。它允许Fortran编译器检查调用中的实际参数与过程的伪参数之间的一致性。这防范了各种程序员的错误。对于Fortran> = 90的某些“高级”功能,显式接口也是必需的;例如,可选或关键字参数。没有明确的接口,编译器将不会生成正确的调用。仅仅包含一个文件并不能提供这些优点。

+1

我会走的更远,我不认为有使用包括文件的任何理由。 – 2013-03-27 17:37:01

+0

@HighPerformanceMark:穷人的泛型编程? – eriktous 2013-03-27 21:11:02

+1

就像我写的*我不知道有什么好的理由使用包含文件*。但是这是一个意见 – 2013-03-27 21:37:38

3

M.S.B的答案很好,可能是选择模块而非include的最重要原因。我想再补充一些想法。

如果这对您来说很重要,那么使用模块可以减少编译后的二进制大小。一个模块被编译一次,当你使用代码的时候,你会象征性地加载该模块。当你include一个文件,你实际上是插入新的代码到你的例程。如果您使用include很多,它可能会导致您的二进制文件很大,同时也增加了编译时间。

您还可以使用模块在Fortran 90中虚拟OOP样式编码,方法是巧妙地使用模块中的公共和私有函数以及用户定义的类型。即使你不想这样做,它也提供了一种很好的方法来将逻辑上属于一起的功能分组。

相关问题