Почему эта функция объявлена ​​внутри модуля и затем используется где-то еще в том же модуле, который не виден компоновщику? - PullRequest
3 голосов
/ 19 октября 2010

У меня есть функция (на случай, если кому-то интересно, это эта функция ) в модуле, который выглядит следующим образом

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 ]

4 голосов
/ 31 октября 2010

Ниже я объясню, используя полный пример ниже (который вы можете скомпилировать и связать, чтобы попробовать что-то):

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 с именем foo. Поскольку вы этого не делаете (функция модуля не является внешней), он не может связать. Вы можете предоставить внешнюю функцию foo, добавив следующий код (не в модуле, просто в конце того же файла):

integer function foo ()
  foo = 42
end function

Если вы добавите это тело функции, то ваш код скомпилируется, и результат будет 42 (так как вызывается внешняя функция, а не функция модуля).

Также стоит отметить, что если вы закомментируете строку integer :: foo в коде bar, символ foo будет преобразован в функцию модуля, которая будет вызываться независимо от того, предоставляете ли вы внешнюю функцию с именем foo (таким образом, вывод будет 1).

Вывод: не ошибка компилятора, а неправильное использование старой функции языка (внешние объявления). Если честно, я думаю, что лучше пометить ваши external декларации как таковые, что, по крайней мере, выделило бы проблему здесь.

1 голос
/ 23 октября 2010

Судя по неполному исходному коду, который вы разместили, я думаю, что это может быть ошибочная строка:

CHARACTER(LEN=255) :: strtok

Поскольку подпрограмма DO_SOMETHING и функция strtok находятся в одном модуле, они автоматически узнают об определении друг друга (у них есть явный интерфейс). Это означает, что не только нет необходимости переопределять тип функции strtok внутри DO_SOMETHING, но на самом деле происходит то, что эта строка объявляет новую символьную переменную с именем strtok в области действия подпрограммы DO_SOMETHING, отменяя Функция модуля с тем же именем.

По сути, внутри подпрограммы идентификатор strtok относится к переменной, поэтому, когда вы пытаетесь обратиться к функции с таким именем, компилятор не знает об этом.
Хм, теперь, когда я пишу это, я начинаю думать, что это должно дать ошибку времени компиляции, а не ошибку компоновки. Тем не менее, возможно, стоит попытаться закомментировать строку, которую я упомянул, и попробовать.

...