Доступ к переменным модуля 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_;