2016-01-22 3 views
2

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

предположит, что код в FORtran модуля: реальных * 8, размещаемый, размер (:,:, :) :: х

Я cretaed переменного тока двойного указателя, как:

extern "C" { double* common_area_mp_x_; }

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

Спасибо, Mindbender

+0

Отсутствующие 'extern'? –

+0

Нет, на самом деле у меня есть декларация на стороне С с внешним. Я просто отредактирую и уменьшу эту путаницу .. спасибо .. – mindbender

+0

Поскольку это только базовая переменная (а не структура, функция или класс), возможно, вы можете оставить «double * common_area_mp_x_» из заголовочных файлов, если это необходимо, а затем объявить 'extern double * common_area_mp_x_' в файле C++, где вы ссылаетесь на эту переменную. –

ответ

5

Fortran 2003 введена совместимость с C в стандартной Фортране. Если у вас нет веских оснований для обратного, вы должны использовать средства, предоставляемые этой функцией языка. См. Здесь тег на этом сайте.

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

С точки зрения реализации, компилятор Fortran будет использовать дескриптор для хранения статуса распределения переменной, подлежащей распределению. Для этого дескриптора есть больше, чем просто указатель на данные - см. «Обработка дескрипторов массива 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; 
+0

Согласно моему тесту, проблема, похоже, не в стороне fortran, а в использовании 'extern 'C" double * ptr', когда '' extern double * ptr' должен был использоваться в коде C++. –

+0

@ J.J.Hakala Со стороны Фортрана BIND (C) по совместимым аргументам устраняет проблему. Существуют другие скрытые проблемы с подходом OP. Это 2016 год ... Есть очень мало действительных оправданий за то, что они не пишут стандартный код соответствия для такого рода проблем. – IanH

+0

ah ok, теперь я прочитал профайлу fortran-iso-c-binding. –

2

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

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

с гну инструментов

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

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

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

extern double * common_area_mp_x_; 

 Смежные вопросы

  • Нет связанных вопросов^_^