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

В настоящее время я работаю над проектом, который требует интеграции кода 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

2

Решение

В Fortran 2003 появилась совместимость с C в стандартном языке 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;
6

Другие решения

Учитывая файл 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_;
2

По вопросам рекламы [email protected]