Связывание C ++ и Fortran

Я хочу объединить C ++ и Fortran вместе. Мой код Fortran будет использовать функцию C ++, а функция C ++ изменяет переменные Fortran и отправляет их обратно. Функция C ++ построена с использованием других кодов C ++, например. функция C ++ будет использовать некоторую подфункцию в другом файле .cpp. Я делаю код Fortran с ifort и добавляю эту функцию C ++ как один объектный файл test.o в свой make-файл Fortran. Я также поместил все необходимые файлы C ++ .o (support test.o) в make-файл. Показывает ошибку

# 6633, «Тип фактического аргумента отличается от типа фиктивного аргумента».

Вот код.

Код Фортрана

  use, intrinsic :: ISO_C_BINDING, only: C_INT, C_DOUBLE   
  implicit double precision(a-h,o-z),integer(i-n)
  Interface
   integer (C_INT) function SolveBIE_(x, y, aa, m) BIND(C, NAME='SolveBIE_')
   use, intrinsic :: ISO_C_BINDING
   implicit none
   type (C_PTR), value :: x
   type (C_PTR), value :: y
   type (C_PTR), value :: aa
   integer (C_INT), value :: m
   end function SolveBIE_
  end Interface
  integer (C_INT) :: m
  real (C_DOUBLE), ALLOCATABLE, DIMENSION(:,:), target :: x
  real (C_DOUBLE), ALLOCATABLE, DIMENSION(:,:), target :: y
  real (C_DOUBLE), ALLOCATABLE, DIMENSION(:,:), target :: aa
  ALLOCATE(x(0:MAXLEN,MAXINTERFACES))
  ALLOCATE(y(0:MAXLEN,MAXINTERFACES))
  ALLOCATE(aa(0:MAXLEN,MAXINTERFACES))

Запуск моего кода Fortran

  mm = SolveBIE_(x(1,1),y(1,1),aa(1,1),m) 

Используя код C ++ и откуда взялась ошибка, на x, y, aa я использую x(1,1) вместо x, потому что при использовании x возникает другая ошибка

# 6634, "нарушены правила соответствия форм фактических аргументов и фиктивных аргументов" `

Я не понимаю, почему это должно быть x(1,1). Почему это работает, а не x?

Мой код на C ++

  #ifdef __cplusplus
  extern "C" {
  #endif
  int solveBIE_(double *ini_bdry_x, double *ini_bdry_y, double *ini_bdry_um, int *fM)
{  
     double(*bdry_node)[2] = new double[M1][2];
     for (int k = 0; k < M; k++) {
        bdry_node[k+1][0] = ini_bdry_x[k+1];
        bdry_node[k+1][1] = ini_bdry_y[k+1];
        bdry_theta[k+1] = Atan(ini_bdry_x[k+1], ini_bdry_y[k+1]);}

    ... some functions in other .cpp file

person Yue    schedule 06.02.2018    source источник
comment
Следуйте этому руководству и попроси о помощи, когда ты застрял   -  person Victor M Herasme Perez    schedule 06.02.2018
comment
Было бы полезно немного разбить этот первый абзац. А также дать полное сообщение об ошибке. Однако сообщение об ошибке, если оно относится к аргументам SolveBIE_, кажется мне совершенно ясным (type(c_ptr) и real(c_double) не одно и то же). Что вы в этом не понимаете?   -  person francescalus    schedule 06.02.2018
comment
Я не совсем понимаю, о чем вы говорите. Особенно о x и x(1,1). Пожалуйста, всегда показывайте полный код и полное сообщение об ошибке (или весь вывод).   -  person Vladimir F    schedule 06.02.2018
comment
@VictorHerasmePerez Этот учебник очень устарел. OP использует более современные методы.   -  person Vladimir F    schedule 06.02.2018


Ответы (1)


Как написан ваш интерфейс, вы должны построить C_PTR в массив x и передать его в качестве первого аргумента:

use, intrinsic :: ISO_C_BINDING, only: C_INT, C_DOUBLE, C_PTR, C_LOC
! ...
type(C_PTR) PTRx
! ...
PTRx = C_LOC(x(LBOUND(x,1),LBOUND(x,2)))
! ...
mm = solveBIE_(PTRx, PTRy, PTRaa, m)

Как показано выше, вам также придется исправить следующие два аргумента. Но вам нужно переписать интерфейс для аргумента fM, потому что по существу Fortran будет передавать целое число по значению, тогда как C ++ ожидает указатель. Учитывая это, я бы полностью переписал интерфейс, используя имена, указанные для аргументов в функции C ++, и передавая все по ссылке. Имена фиктивных аргументов потенциально видны в Фортране, поэтому полезно, чтобы они имели смысл. Далее я предполагаю, что fM указывает на скаляр в вызываемом объекте:

  Interface
   function SolveBIE_(ini_bdry_x, ini_bdry_y, ini_bdry_um, fM) &
      BIND(C, NAME='SolveBIE_')
   import
   implicit none
   integer(C_INT) SolveBIE_
   real(C_DOUBLE) :: ini_bdry_x(*)
   real(C_DOUBLE) :: ini_bdry_y(*)
   real(C_DOUBLE) :: ini_bdry_um(*)
   integer (C_INT) :: fM
   end function SolveBIE_
  end Interface

Позже вы можете вызывать его более или менее нормально как

mm = SolveBIE_(x,y,aa,m)

Обратите внимание, что x(1,1) был неправильным, потому что LBOUND(x,1) = 0, а не 1!

person user5713492    schedule 06.02.2018
comment
Спасибо за совет. У меня вопрос, следует ли мне использовать тот же способ определения ini_bdry_x (*), например real (C_DOUBLE), ALLOCATABLE, DIMENSION (:, :), target :: x ALLOCATE (x (0: MAXLEN, MAXINTERFACES)) Потому что мне нужно установить для них значение, а затем передать их в C ++. Поэтому сначала необходимо их определить. - person Yue; 08.02.2018
comment
Правильно, вы должны делать все то другое, что вы уже делаете. Я не собирался переписывать для вас всю вашу программу, а просто хотел представить изменения, которые я внесу. - person user5713492; 09.02.2018
comment
Спасибо. Сейчас ошибки нет. Но у меня ошибка компиляции. Я разместил еще один вопрос. Вот ссылка: https://stackoverflow.com/questions/48696645/compile-error-when-binding-c-and-fortran - person Yue; 12.02.2018