INCLUDE与Fortran中的模块之间的区别

时间:2013-03-27 15:13:10

标签: module include fortran

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

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

3 个答案:

答案 0 :(得分:23)

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

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

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

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

示例问题:

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

    INTEGER :: i

    在隔离中,它看起来像将i名称声明为整数标量(或者可能是函数?谁知道!)。现在考虑包括以上内容的以下范围:

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

    i现在是排名第二的阵列!也许你想让它成为一个指针?可分配?一个虚拟的论点?也许这会导致错误,或者它可能是有效的来源!将隐式打字投入到混音中以真正增加潜在的乐趣。

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

  • Fortran对语句排序有限制(规范语句必须在可执行语句之前等)。包含的源也受到这些限制,再次在包含点的上下文中,而不是源定义的点。

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

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

  • 想要在相关程序中共享一些全局状态,并且您想使用include吗?让我向您介绍常见的块以及序列关联的相关基本概念......

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

    模块变量完全不需要公共块及其相关的邪恶。

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

    如上所述 - 编译器自动获得模块过程接口的知识(编译器知识是"显式"因为它实际上看到了过程的代码 - 因此术语"显式界面")。程序员不需要做更多的事情。

    上述结果是外部子程序不应该在所有中使用,除非有充分的理由相反(可能存在循环或过度广泛的依赖) - 基本出发点应该将所有放在模块或主程序中。

其他海报提到了模块的源代码组织优势 - 包括对相关程序和其他东西进行分组的能力。进入一个包,控制内部实现细节的可访问性。

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

第二个有效用途是克服通用编程技术(C ++中提供的模板)的语言缺乏支持 - 即操作中涉及的对象类型可能不同,但描述内容的令牌序列对那些物体做的基本相同。在语言对其进行排序之前,可能还需要十年左右的时间。

答案 1 :(得分:7)

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

答案 2 :(得分:3)

M.S.B.的答案很棒,可能是偏好包含模块的最重要原因。我想补充几点想法。

使用模块会减少编译的二进制文件大小,如果这对您很重要。一个模块被编译一次,当你use它时,你象征性地加载该模块以使用代码。当您include文件时,您实际上是将新代码插入到例程中。如果你经常使用include,可能会导致二进制文件变大,并且还会增加编译时间。

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