为什么这是在模块内部声明的函数,然后在链接器看不到的同一模块中的其他地方使用?

时间:2010-10-19 17:05:46

标签: fortran gfortran

我在一个看起来像这样的模块中有一个函数(如果有人有兴趣,它是this function

MODULE MYMODULE

    IMPLICIT NONE
    ! Some random stuff
    CONTAINS

        CHARACTER*255 FUNCTION strtok ( source_string, delimiters )
         [...]
        END FUNCTION strtok

        SUBROUTINE DO_SOMETHING ( )
           CHARACTER(LEN=255) :: strtok
           [...] ! 
        END SUBROUTINE DO_SOMETHING

END MODULE MYMODULE

strtok函数是C的字符串标记化器的一个版本,我将在DO_SOMETHING子例程中使用此函数。我需要定义strtok,否则gfortran会抱怨它没有被定义。但是,如果我这样做,并编译我的代码并将其链接到主程序,链接器会抱怨对strtok_的未定义引用。我不知道为什么会这样,因为它们都在同一个模块中,应该是可见的。同一模块中的其他功能和子程序没有此问题。这是否与这个字符* - 回归功能有关?

2 个答案:

答案 0 :(得分:4)

在下文中,我将使用下面的完整示例(您可以编译和链接来尝试)来解释:

module mymodule
contains
  integer function foo ()
    foo = 1
  end function

  integer function bar ()
    integer :: foo
    bar = foo()
  end function
end module

program test
  use mymodule
  print *, bar()
end

在函数bar的代码中,声明integer :: foo严格等同于:

integer, external :: foo

因此,在bar的代码中,您明确说明:

  

“可能已经有了名字的象征   foo您可以访问,但从现在开始   当我使用它时,我的意思是它是一个   此名称的外部功能“

所以,这是有效的代码,编译器只希望你提供一个名为external的{​​{1}}函数。因为你没有(模块功能不是外部的),它无法链接。您可以通过添加以下代码(不在模块中,仅在同一文件的末尾)提供外部foo功能:

foo

如果添加此函数体,则代码将编译,输出将为integer function foo () foo = 42 end function (因为调用外部函数,而不是模块函数)。

另外值得注意的是,如果您在42的代码中注释掉integer :: foo行,则符号bar将解析为模块函数,无论您是否提供该模块函数一个名为foo的外部函数(因此,输出将为foo)。

结论:不是编译器错误,而是滥用语言的旧功能(外部声明)。说实话,我认为最好明确标记你的1声明,这至少会在这里强调这个问题。

答案 1 :(得分:1)

从您发布的不完整源代码判断,我认为这可能是违规行:

CHARACTER(LEN=255) :: strtok

由于子例程DO_SOMETHING和函数strtok在同一模块中,因此它们会自动了解彼此的定义(它们具有显式接口)。这意味着不仅没有必要在strtok内重新声明函数DO_SOMETHING的类型,但实际发生的是该行在子例程范围内声明了一个名为strtok的新字符变量DO_SOMETHING,使用相同的名称覆盖模块函数。

基本上,在子例程中,标识符strtok引用变量,因此当您尝试通过该名称引用函数时,编译器不知道它。
嗯,既然我正在写这个,我开始认为这应该给出编译时错误,而不是链接错误。尽管如此,尝试评论我提到的那条线并试一试可能是值得的。