Доступ к переменным модуля Fortran из C++

В настоящее время я работаю над проектом, который требует интеграции кода Fortran в C++. В модуле fortran объявлено множество переменных и массивов. Я могу получить доступ к типам integer,float и double из c, объявив переменную ac как extern double common_area_mp_rmax_, когда соответствующее объявление fortran является действительным *8 rmax и имя модуля - common_area. Однако, когда я пытаюсь сделать то же самое для массива, я получаю ошибку.

предположим, что код в модуле fortran: real*8, размещаемый, размерность (:,:,:):: x

Я обозначил двойной указатель переменного тока как:

extern "C" { double* common_area_mp_x_; }

Теперь, когда я компилирую весь проект, он говорит: "множественное определение variable_area_mp_x_". Я использую CMake для компиляции всего проекта. Может кто-то пролить свет на то, что я делаю неправильно? Я новичок в Фортране, и мне становится трудно это исправить. Я ценю ваше время и помощь.

Спасибо, умник

2 ответа

Решение

В Fortran 2003 появилась совместимость с C в стандартном языке Fortran. Если у вас нет веских причин для обратного, вы должны использовать возможности, предоставляемые этой языковой функцией. Смотрите тег /questions/tagged/fortran-iso-c-binding на этом сайте для примеров.

В соответствии с текущим стандартом Fortran (и в проекте следующей редакции стандарта) переменная модуля Fortran, размещаемая в модуле, не совместима с переменной C.

С точки зрения реализации, компилятор Фортрана будет использовать дескриптор для хранения статуса размещения выделяемой переменной. В этом дескрипторе есть нечто большее, чем просто указатель на данные - см. "Обработка дескрипторов массивов Fortran" в Руководстве пользователя и справочнике компилятора для получения дополнительной информации.

Лучший подход к обмену информацией в этом случае зависит от того, что вы пытаетесь сделать. Один из вариантов - присвоить выделяемому массиву атрибут TARGET, а затем иметь отдельную переменную TYPE(C_PTR) с меткой привязки с C-адресом цели. Такие аспекты, как размер массива, необходимо сообщать отдельно.

MODULE common_area
  USE, INTRINSIC :: ISO_C_BINDING, ONLY: C_PTR, C_DOUBLE
  IMPLICIT NONE
  ...
  REAL(C_DOUBLE), ALLOCATABLE, TARGET :: x(:,:,:)
  TYPE(C_PTR), BIND(C, NAME='x_ptr') :: x_ptr
CONTAINS
  ! Call before operating on x_ptr in C++
  SUBROUTINE init
    USE, INTRINSIC :: ISO_C_BINDING, ONLY: C_LOC
    ALLOCATE(x(1,2,3))
    x_ptr = C_LOC(x)
  END SUBROUTINE init

~~~

// After init has been executed, this is a 
// pointer to the value of the allocatable module variable
extern "C" double *x_ptr;

Имеется файл C++ test.cpp с содержимым

extern "C" { double * foo; }
extern double bar;
double asdf;

с инструментами GNU

g++ -Wall -c test.cpp; nm test.o
> 0000000000000000 B asdf
> 0000000000000008 B foo

т.е. использование первого параметра фактически вводит новый символ с этим именем.

В этом случае правильный выбор будет

extern double * common_area_mp_x_;
Другие вопросы по тегам