【问题标题】:how can I access a C pointer from fortran?如何从 fortran 访问 C 指针?
【发布时间】:2012-12-06 08:36:12
【问题描述】:

我像这样将值分配给状态数组:

状态[i] += 1;

我喜欢从 fortran 访问这个数组
我怎样才能访问这个数组?
例如,我想像这样从 fortran 更改 STAT 的值:

STAT(2)=3

这可能吗?

c 源代码

#include <stdio.h>
#include <stdlib.h>
#include <sys/shm.h>
#include <sys/stat.h>

void call_fc_ (int *key, int *addr, int *size, int *status)
{
    int i;
    int shmid;
    void* shared_addr;

    //printf("first ptr = %p\n", *addr);

    shmid = shmget (*key, *size, IPC_CREAT | IPC_EXCL | 0666);
    if (shmid == -1)
    {
        printf("shmget is failed!\n");
        exit(0);
    }
    shared_addr = (void*) shmat(shmid, 0, 0);
    status = (int*)shared_addr;
    //printf("status ptr = %p\n", status);

    int data_size = *size/sizeof(int);

    for(i=0; i<data_size;i++) {
        status[i] += 1;
        printf("%d th value : %d \n", i, status[i]);
    }
}

fortran 源码

IMPLICIT NONE
INTEGER*8 KEY,SIZE,ADDR
DATA KEY  / 777 /
DATA SIZE / 64 /
!DATA ADDR / Z'b76fb000' /

CALL CALL_FC(KEY, ADDR, SIZE, STAT)

PRINT *, 'stat is : ', STAT

! CAN I ACCESS TO STAT LIKE THIS?
!DO I=1,10
!STAT(I) = STAT(I) + 5
!WRITE (*,*) STAT(I)
!END DO

我已经测试过这段代码,我参考了这个问题的好答案。 但是当我尝试这样做时出现分段错误错误:

integer(c_int) :: key = 777, ssize = 64, addr
integer, pointer, dimension(:) :: stat
type(c_ptr) :: statptr

!DATA KEY  / 777 /
!DATA SIZE / 64 /


print *, 'before stat size = ', size(stat)
call call_fc(key, addr, ssize, statptr)
!print *, 'statptr = ', statptr
call c_f_pointer(statptr, stat, [ssize])
print *, 'after stat size = ', size(stat)

stat(1) = 111 <==
stat(2) = 222
stat(3) = 333

print *, 'stat : ', stat

你能认出是怎么回事吗?

【问题讨论】:

    标签: c fortran fortran-iso-c-binding


    【解决方案1】:

    你必须以某种方式声明 STAT。如果你开始玩动态内存分配,留在 FORTRAN 77 是没有希望的。也许有人能想出一些解决方案,但这是我发现的最小变化。它使用 Fortran 2003 与 C 的互操作性。(也许 Cray 指针解决方案会更短,但非标准)

    USE ISO_C_BINDING
    
    IMPLICIT NONE
    
    
    INTEGER(C_INT) KEY,SIZE,ADDR,I
    DATA KEY  / 777 /
    DATA SIZE / 64 /
    !DATA ADDR / Z'b76fb000' /
    INTEGER,POINTER  :: STAT(:)
    TYPE(C_PTR) :: STATPTR
    
    CALL CALL_FC(KEY, ADDR, SIZE, STATPTR)
    
    call C_F_POINTER(STATPTR,STAT,(/SIZE/))
    
    PRINT *, 'stat is : '
    DO I=1,SIZE
      PRINT *,STAT(I)
    END DO
    
    ! CAN I ACCESS TO STAT LIKE THIS?
    !DO I=1,10
    !STAT(I) = STAT(I) + 5
    !WRITE (*,*) STAT(I)
    !END DO
    END
    

    我从你的 C 部分得到了一些错误,我没有检查。我也不确切知道该程序应该做什么。

    不过,我真的鼓励您使用现代 Fortran 功能。最重要的是 ISO_C_BINDING 用于 C 和 Fortran 之间的互操作性。也忘记DATA 语句并使用变量初始化。

    快速翻译成更现代的 Fortran:

      use iso_c_binding
    
      implicit none
    
      interface
        subroutine call_fc(key,addr,size,status) bind(C,name='call_fc_')
          import
          integer(c_int) :: key  !intents should be added
          integer(c_int) :: addr
          integer(c_int) :: size
          type(c_ptr) :: status
        end subroutine
      end interface
    
    
    
      integer(c_int) :: key = 777, size=64,addr,i
      integer(c_int),pointer  :: stat(:)
      type(C_ptr) :: statptr
    
      call call_fc(key, addr, size, statptr)
    
      call c_f_pointer(statptr,stat,(/size/))
    
      print *, 'stat is : ',stat
    
    end
    

    【讨论】:

    • +1:但我已经到了我认为现在帮助人们编写 FORTRAN77 是不道德的阶段;我会帮助他们重写它,但没有充分的理由在 FORTRAN77 中编写新代码。
    • 最好也为那里的例程弹出一个接口块。 OP 还应该用INTEGER(C_INT) 替换非标准的INTEGER*8,否则在许多当前系统上可能存在整数大小不匹配。
    • 整数类型你肯定是对的,这是不兼容的。
    猜你喜欢
    • 2015-04-17
    • 2016-02-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-07-09
    相关资源
    最近更新 更多