Передача двумерного массива из Fortran в C

У меня возникли проблемы с передачей двумерного массива из Fortran в C. Ниже приведена моя функция C, которая просто отображает элементы массива на экране.

#include <stdio.h>
void print2(double *arr , int *n)
{
    int y = *n;
    printf("\n y = %d", y);
    for(int i =0; i<y; i++)
    {
          for (int j = 0; j < y; j++)
              printf("%.6g", *((arr + i*y) + j));
          printf("\n");
    }
}

Мой код Fortran до сих пор выглядит следующим образом:

program linkFwithC
    use, intrinsic :: iso_c_binding
    implicit none
    real, dimension(3,3)::a
    a(1,1)=1
    a(1,2)=2
    a(1,3)=3
    a(2,1)=4
    a(2,2)=5
    a(2,3)=6
    a(3,1)=7
    a(3,2)=8
    a(3,3)=9

    interface
        subroutine print2(a,n) bind( c )
        use, intrinsic :: iso_c_binding
        type(c_ptr)::a
        integer(C_INT)::n
        end subroutine print2   
    end interface

    call print2(c_loc(a),3)
end program linkFwithC

Я связываю оба файла, создавая статическую библиотеку для функции C и создавая файл .lib. После сборки файла .lib я добавляю его в проект fortran и запускаю проект fortran. Код выполняется без ошибок, и значение n отображается правильно; Однако все отображаемые значения массива неверны.

Пожалуйста помоги !

Спасибо, Анас


person Anas    schedule 20.12.2014    source источник
comment
где вы вызываете print2 (без эксперта по фортрану). также, вероятно, было бы хорошо сначала распечатать n в вашей c-функции, если это 0, то вывода не будет   -  person AndersK    schedule 20.12.2014
comment
Это правда, я только что добавил вызов и получил следующие две ошибки:   -  person Anas    schedule 20.12.2014
comment
ошибка № 6631: при вызове процедуры с явным интерфейсом должен присутствовать необязательный фактический аргумент. [A] ошибка № 6631: необязательный фактический аргумент должен присутствовать при вызове процедуры с явным интерфейсом. [н]   -  person Anas    schedule 20.12.2014
comment
я не вижу никакого вызова print2(a,3)?   -  person AndersK    schedule 20.12.2014
comment
Я добавил вызов в предпоследней строке (вызов print2(a,n)). Кажется, что аргументы между вызовом и функцией разные! Каждый раз, когда я пытаюсь запустить, появляется следующая ошибка: ошибка № 6634: Нарушены правила сопоставления форм фактических аргументов и фиктивных аргументов. [A]   -  person Anas    schedule 20.12.2014
comment
Разве «настоящий» в фортране не 4 байта, а «двойной» в C 8 байтов?   -  person brm    schedule 20.12.2014
comment
Вам нужно объявить аргументы print2 в блоке интерфейса.   -  person M. S. B.    schedule 20.12.2014
comment
Я изменил код и объявил аргументы функций C внутри своего интерфейса. Код работает нормально, но значение n, которое видит функция C, равно 1987654, а не 3. См. отредактированный код в вопросе выше.   -  person Anas    schedule 20.12.2014
comment
Пробовали ли вы использовать либо «float» вместо «double», либо указать «real * 8» вместо «real»?   -  person brm    schedule 20.12.2014
comment
Хорошо, я получил целое число в C. Ошибка была в том, что fortran вызывает по ссылке, а C вызывает по значению. Когда я добавил * перед n в аргументах функции C, я получил n правильное, но все значения массива были неправильными. Не могли бы вы проверить, правильно ли я передаю массив.   -  person Anas    schedule 20.12.2014


Ответы (2)


В коде есть несколько проблем, как показано [в настоящее время].

  • Аргумент n в интерфейсе Fortran для print2 не имеет атрибута VALUE, однако соответствующий параметр в функции C принимается по значению. Рассмотрите возможность добавления VALUE к объявлению Fortran.

  • Та же проблема возникает с указателем на массив. Интерфейс Fortran передает указатель без значения, функция C ожидает «указатель по значению» (в отличие от указателя на указатель). Обратите внимание, что здесь нет необходимости явно использовать C_PTR — вы можете создать интероперабельный интерфейс, используя фактический тип массива.

  • На большинстве платформ значение REAL по умолчанию в Fortran не совпадает с двойным значением в C — рассмотрите возможность использования констант типа из ISO_C_BINDING, чтобы убедиться, что тип REAL на стороне Fortran соответствует типу C.

  • C_LOC требует, чтобы его аргумент имел атрибут TARGET. Добавьте этот атрибут в объявление переменной a в основной программе.

person IanH    schedule 20.12.2014
comment
Не могли бы вы подробнее рассказать о своем последнем замечании относительно C_LOC. Мое намерение в коде состояло в том, чтобы передать адрес первого элемента массива a функции C. - person Anas; 20.12.2014

После дальнейших исследований я смог найти обходной путь следующим образом:

Ниже приведена моя функция C:

#include <stdio.h>
void print2(void *p, int n) {
  printf("Array from C is \n");
  double *dptr;
  dptr = (double *)p;
  for (int i = 0; i < n; i++) {
    for (int j = 0; j<n; j++)
      printf("%.6g \t",dptr[i*n+j]);
    printf("\n");
  }
}

Ниже приведен мой код Fortran:

program linkFwithC
use iso_c_binding
implicit none 
interface
  subroutine my_routine(p,r) bind(c,name='print2')
    import :: c_ptr
    import :: c_int
    type(c_ptr), value :: p
    integer(c_int), value :: r
  end subroutine
end interface


integer,parameter ::n=3
real (c_double), allocatable, target :: xyz(:,:)
real (c_double), target :: abc(3,3)
type(c_ptr) :: cptr
allocate(xyz(n,n))
cptr = c_loc(xyz(1,1))

!Inputing array valyes

xyz(1,1)= 1
xyz(1,2)= 2
xyz(1,3)= 3
xyz(2,1)= 4
xyz(2,2)= 5
xyz(2,3)= 6
xyz(3,1)= 7
xyz(3,2)= 8
xyz(3,3)= 9


call my_routine(cptr,n)
deallocate(xyz)
pause
end program linkFwithC
person Anas    schedule 01.01.2015