Доступ к массивам 2d, переданным из C как указатели в Fortran

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

    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
    REAL, POINTER :: PTR2
    integer i,j
    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)

    do j=1,n
    do i=1,n

    print*,"xyz(i,j)",i,j,xyz(j,i)

    enddo
    enddo
    deallocate(xyz)
 ! pause
  end program linkFwithC

Ниже мой код C

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

      *(p+i*n+j)=1;
      printf("\n");
     }
  }
 }

Ниже приведен вывод

Array from C is
1       4       7
1       5       8
1       6       9
 xyz(i,j)           1           1   1.00000000000000
 xyz(i,j)           2           1   1.00000000000000
 xyz(i,j)           3           1   1.00000000000000
 xyz(i,j)           1           2   4.00000000000000
 xyz(i,j)           2           2   5.00000000000000
 xyz(i,j)           3           2   6.00000000000000
 xyz(i,j)           1           3   7.00000000000000
 xyz(i,j)           2           3   8.00000000000000
 xyz(i,j)           3           3   9.00000000000000
*** glibc detected *** ./main.exe: free(): invalid next size (normal): 0x000000000093c290 ***
======= Backtrace: =========
/lib64/libc.so.6[0x320ea75f4e]
/lib64/libc.so.6[0x320ea78cf0]
./main.exe[0x408786]
./main.exe[0x4240bc]
./main.exe[0x429f54]
./main.exe[0x402e63]
/lib64/libc.so.6(__libc_start_main+0xfd)[0x320ea1ed5d]
./main.exe[0x402d69]
======= Memory map: ========

Я не могу распечатать измененные значения на Фортране. Может ли кто-нибудь предположить, что может быть возможной причиной выхода заработной платы?


person user1131484    schedule 30.09.2016    source источник
comment
вы уже задавали много таких вопросов: c">stackoverflow.com/questions/27584674/, stackoverflow.com/questions/27582715/   -  person Jean-François Fabre    schedule 30.09.2016
comment
Вы уверены, что двумерные выделяемые массивы в фортране имеют непрерывную память, как статические двумерные массивы? Потому что результат, кажется, доказывает обратное. И не забывайте, что C и FORTRAN транспонируются, когда речь идет о многомерных массивах.   -  person Jean-François Fabre    schedule 30.09.2016
comment
@ Jean-FrançoisFabre Да, на самом деле они всегда являются непрерывной памятью. Вы можете поискать в Google пример программы, которая передает указатель из c в lapack фортран.   -  person Iharob Al Asimi    schedule 01.10.2016
comment
@iharob Я спрашивал, потому что это выглядело так, как будто это не так, ты согласен? Я вообще не специалист по FORTRAN. Просто подливаю масла в дискуссию :)   -  person Jean-François Fabre    schedule 01.10.2016
comment
не могли бы вы отредактировать свой код C и заменить *(p+i*n+j)=1; на *(p+i*n+j)=i*n+j; (и, конечно, связанный с ним вывод).   -  person Jean-François Fabre    schedule 01.10.2016
comment
По какой причине вы не используете 2D-массив в коде C? И никогда не используйте ненужные приведения! И p, и dptr имеют один и тот же тип, так зачем приведение?   -  person too honest for this site    schedule 01.10.2016
comment
@Olaf C не имеет настоящих 2D-массивов, за исключением ограниченных статических и VLA. Вы должны создать массив указателей на строку в C, и это раздражает.   -  person Vladimir F    schedule 01.10.2016
comment
@VladimirF: Это ерунда! Вы можете объявлять многомерные массивы везде, где вы можете объявлять другие объекты, передавать указатели на них в/из функций и, конечно же, без проблем распределять их динамически. Просто многие люди не понимают синтаксиса и используют зубчатые массивы (которые действительно раздражают, если вы хотите двумерный массив)! Но дело не в языке, а в кодерах.   -  person too honest for this site    schedule 01.10.2016
comment
@Olaf Это совсем не глупость! Довольно сложно создать 2D-непрерывный динамический массив в C. Вам ДЕЙСТВИТЕЛЬНО нужно создавать 1D-массив указателей отдельно.   -  person Vladimir F    schedule 01.10.2016
comment
@VladimirF: int (*a2d)[COLS] = malloc(ROWS * sizeof(*a2d)); ... ; free(a2d); сложно? Хорошая шутка! Как я уже писал: эту чушь распространяют люди, не знающие языка! О, и, несмотря на использование заглавных букв, ROWS и COLS тоже могут быть переменными!   -  person too honest for this site    schedule 02.10.2016
comment
@ Олаф Я хорошо это знаю, не волнуйся, это достаточно запутанно.   -  person Vladimir F    schedule 02.10.2016
comment
@VladimirF: я не вижу ничего запутанного. Это только в том случае, если вы правильно не поняли декларации и приоритет. Это намного проще, чем зубчатый массив, и действительно гарантируется непрерывность. Если вы хотите что-то более простое, C — не ваш язык.   -  person too honest for this site    schedule 02.10.2016


Ответы (1)


Прежде всего, ваш код не FORTRAN, а Fortran; средства для взаимодействия с языком C появились намного позже. Во-вторых, следующий код

#include <stdio.h>
void print2(double *p, int n)
{  
  double *dptr;
  int i,j;

  /* Why are you making a copy here? 
   * Did you intent to pass by value or reference?
   */
  dptr = p;
  printf("Array from C is \n");
  for(i = 0; i < n; i++){
    for(j = 0; j < n; j++){
      printf("%.6g \t", dptr[i*n+j]);
      *(p+i*n+j)=1;
      printf("\n");
    }
  }
}

module mymod

  use ISO_C_binding, only: &
       c_ptr, &
       c_int

  ! Explicit typing only
  implicit none

  interface
     subroutine my_routine(p, r) bind(c, name='print2')
       import :: c_ptr, c_int
       type(c_ptr), value    :: p
       integer(c_int), value :: r
     end subroutine my_routine
  end interface

end module mymod

program main

    use ISO_Fortran_env, only: &
    compiler_version, &
    compiler_options

    use ISO_C_binding, only: &
     c_double, &
     c_ptr, &
     c_loc

    use mymod, only: &
     my_routine

    ! Explicit typing only
    implicit none

    integer i, j
    integer, parameter :: N = 3
    real(c_double), allocatable, target :: xyz(:,:)
    type(c_ptr) :: cptr

    ! Allocate memory
    allocate(xyz(N, N))

    ! Get C-language address
    cptr = c_loc(xyz(1,1))

    ! Inputting array values
    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)

    do j=1, N
       do i=1, N
      print *, "xyz(i,j)", i, j, xyz(j, i)
       end do   
    end do

    ! Release memory
    deallocate(xyz)

    print '(/4a/)', &
    ' This file was compiled using ', compiler_version(), &
    ' using the options ', compiler_options()

end program main

урожаи

gfortran -Wall -o main.exe  print2.c mymod.f90 main.f90
./main.exe

Array from C is 
1   
4   
7   
2   
5   
8   
3   
6   
9   
 xyz(i,j)           1           1   1.0000000000000000     
 xyz(i,j)           2           1   1.0000000000000000     
 xyz(i,j)           3           1   1.0000000000000000     
 xyz(i,j)           1           2   1.0000000000000000     
 xyz(i,j)           2           2   1.0000000000000000     
 xyz(i,j)           3           2   1.0000000000000000     
 xyz(i,j)           1           3   1.0000000000000000     
 xyz(i,j)           2           3   1.0000000000000000     
 xyz(i,j)           3           3   1.0000000000000000     

 This file was compiled using GCC version 6.1.1 20160802 using the options -mtune=generic -march=x86-64 -Wall
person jlokimlin    schedule 30.09.2016
comment
можешь объяснить что исправил? - person Jean-François Fabre; 01.10.2016
comment
Не могу увидеть никаких изменений - person user1131484; 01.10.2016
comment
да, небольшое изменение в коде c: использовал void *, и это сработало - person user1131484; 01.10.2016