В настоящее время я работаю над проектом, который требует интеграции кода Fortran в C ++. В модуле fortran объявлено множество переменных и массивов. Я могу получить доступ к типам integer, float и double из c, объявив переменную c как extern double common_area_mp_rmax_, когда соответствующее объявление fortran является действительным * 8 rmax и имя модуля — common_area. Однако, когда я пытаюсь сделать то же самое для массива, я получаю ошибку.
Предположим, что код в модуле Fortran:
действительный * 8, размещаемый, размерность (:,:, 🙂 :: x
Я создал c двойной указатель как:
extern "C"{
double* common_area_mp_x_;
}
Теперь, когда я компилирую весь проект, он говорит: «множественное определение variable_area_mp_x_». Я использую CMake для компиляции всего проекта.
Может кто-то пролить свет на то, что я делаю неправильно? Я новичок в Фортране, и мне становится трудно это исправить. Я ценю ваше время и помощь.
Спасибо,
Mindbender
В Fortran 2003 появилась совместимость с C в стандартном языке Fortran. Если у вас нет веских причин для обратного, вы должны использовать возможности, предоставляемые этой языковой функцией. Увидеть Fortran-изо-С-связывания тег на этом сайте для примеров.
В соответствии с текущим стандартом 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_;