3

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

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_. 我不知道为什么会这样,因为它们都在同一个模块中并且应该是可见的。同一模块中的其他函数和子程序没有这个问题。这与这是一个字符*返回函数的事实有关吗?

4

2 回答 2

6

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

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

在 function 的代码中bar,声明integer :: foo严格等价于:

integer, external :: foo

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

“您可能已经可以 foo访问名称的符号,但是从现在开始,当我使用它时,我的意思是它是该名称的外部函数”

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

integer function foo ()
  foo = 42
end function

如果您添加此函数体,那么您的代码将编译,并且输出将是42(因为调用了外部函数,而不是模块函数)。

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

结论:不是编译器错误,而是滥用该语言的旧功能(外部声明)。老实说,我认为最好明确地标记你的external声明,这至少会突出这里的问题。

于 2010-10-31T15:11:04.490 回答
1

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

CHARACTER(LEN=255) :: strtok

由于子程序DO_SOMETHING和函数strtok在同一个模块中,它们自动知道彼此的定义(它们具有显式接口)。这意味着不仅没有必要在strtok里面重新声明函数的类型DO_SOMETHING,而且实际发生的是,这一行声明了一个strtok在 subroutine 范围内命名的新字符变量DO_SOMETHING,否决了具有相同名称的模块函数。

基本上,在子程序内部,标识符strtok指的是一个变量,所以当你试图用那个名字来引用一个函数时,编译器并不知道它。
嗯,现在我正在写这篇文章,我开始认为这应该给出编译时错误,而不是链接错误。尽管如此,尝试注释掉我提到的行并试一试可能是值得的。

于 2010-10-22T23:53:44.680 回答