2012-12-06 14 views
5

I zugewiesenen Wert Status Array wie folgt:Wie kann ich auf einen C-Zeiger von Fortran zugreifen?

Status [i] + = 1;

und Ich mag dieses Array zuzugreifen aus Fortran
wie kann ich auf dieses Array zugreifen?
zum Beispiel möchte ich den Wert von STAT von Fortran wie folgt ändern:

STAT (2) = 3

ist das möglich?

c Quelle

#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 Quelle

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 

ich diesen Code getestet wurden und ich refered auf diese Frage zu guten Antworten. aber ich habe einen Segmentierungsfehler Fehler, wenn ich so zu tun versucht:

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 

können Sie erkennen, was los ist?

Antwort

7

Sie müssen STAT irgendwie deklarieren. Wenn Sie mit der dynamischen Speicherzuweisung beginnen, ist der Aufenthalt in FORTRAN 77 hoffnungslos. Vielleicht kann jemand eine Lösung finden, aber das ist die kleinste Veränderung, die ich für möglich gehalten habe. Es nutzt Fortran 2003 Interoperabilität mit C. (Vielleicht wäre Cray Zeiger Lösung kürzer sein, aber Nicht-Standard)

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 

ich einige Fehler von Ihrem C-Teil bin immer, die ich nicht überprüfen. Ich weiß auch nicht genau, was das Programm machen soll.

Aber ich ermutige Sie wirklich, moderne Fortran-Funktionen zu verwenden. Am wichtigsten ist ISO_C_BINDING für die Interoperabilität zwischen C und Fortran. Vergessen Sie auch DATA Anweisungen und verwenden Sie Variableninitialisierung.

Schnell Übersetzung einer moderneren 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 
+4

+1: aber ich habe auf die Bühne, wo ich denke, dass Menschen zu helfen FORTRAN77 in diesen Tagen zu schreiben, ist unmoralisch; Ich werde ihnen helfen, sie neu zu schreiben, aber es gibt keine guten Gründe, in FORTRAN77 neuen Code zu schreiben. –

+1

Besser Pop ein Interface-Block für die Routine auch dort. Das OP sollte auch den Nicht-Standard "INTEGER * 8" durch "INTEGER (C_INT)" ersetzen, da sonst wahrscheinlich eine Integer-Größen-Nichtübereinstimmung auf vielen aktuellen Systemen vorliegt. – IanH

+0

Sie sind definitiv richtig mit der Integer-Art, die nicht kompatibel ist. –