Intel® Fortran Compiler
Build applications that can scale for the future with optimized code designed for Intel® Xeon® and compatible processors.

Access to data in COMMON block from C code

andrey_i_1
Beginner
447 Views

Hello!

I faced a problem when trying to create mixed language program - C main program and FORTRAN library. In FORTRAN I made a COMMON block with two allocatable arrays, and I want to have access to both of them from C code. Everything is fine during building and with access to the first one, but while running program can't obtain correct address of the second array (its address is 0x00000004) and breaks with error. Text of both codes is below.

Any suggestion will be highly appreciated - is it possible to correct the code somehow, or I need to create additional subroutine to access data in COMMON block. Of course, I can make several COMMONs for each array, but it also is not convenient.

Thanks for your answer and help.

FORTRAN code*****************************************************

C------------------------------------------------
    SUBROUTINE ALLOC_ARRAYS
    COMMON /MYARRS/ IAR1,IAR2
    INTEGER, DIMENSION(:), POINTER :: IAR1
    INTEGER, DIMENSION(:), POINTER :: IAR2
    INTEGER I
C--------
    ALLOCATE(IAR1(100),IAR2(100))
    DO I = 1,100
        IAR1(I) = I*12
        IAR2(I) = I*10
    END DO
C--------
    END
C------------------------------------------------
    SUBROUTINE DEALLOC_ARRAYS
    COMMON /MYARRS/ IAR1,IAR2
    INTEGER, DIMENSION(:), POINTER :: IAR1
    INTEGER, DIMENSION(:), POINTER :: IAR2
C--------
    DEALLOCATE(IAR1,IAR2)
C--------
    END
C------------------------------------------------

C code*****************************************************

struct for_arrays
{
    int *piAR1;
    int *piAR2;
};

extern "C"
{
    void ALLOC_ARRAYS();
    void DEALLOC_ARRAYS();

    struct for_arrays MYARRS;
}

void main()
{
    ALLOC_ARRAYS();

//    O.k. here
    int it1 = MYARRS.piAR1[5];
//    Error here
    int it2 = MYARRS.piAR2[6];

    DEALLOC_ARRAYS();
}

 

0 Kudos
1 Solution
Steven_L_Intel1
Employee
447 Views

You can't share pointers to deferred-shape arrays in COMMON. I think the following modification would work, though.

    MODULE ARRAYS_MOD
    USE, INTRINSIC :: ISO_C_BINDING
    TYPE(C_PTR) :: P_IAR1, P_IAR2
    COMMON /MYARRS/ P_IAR1, P_IAR2
    BIND(C) :: /MYARRS/
    INTEGER, DIMENSION(:), POINTER :: IAR1
    INTEGER, DIMENSION(:), POINTER :: IAR2
    END MODULE ARRAYS_MOD
C------------------------------------------------
    SUBROUTINE ALLOC_ARRAYS
    USE ARRAYS_MOD
    INTEGER I
C--------
    ALLOCATE(IAR1(100),IAR2(100))
    P_IAR1 = C_LOC(IAR1)
    P_IAR2 = C_LOC(IAR2)
    DO I = 1,100
        IAR1(I) = I*12
        IAR2(I) = I*10
    END DO
C--------
    END
C------------------------------------------------
    SUBROUTINE DEALLOC_ARRAYS
    USE ARRAYS_MOD
C--------
    DEALLOCATE(IAR1,IAR2)
C--------
    END

Do keep in mind that Fortran arrays are 1-origin and C arrays are 0-origin.

View solution in original post

0 Kudos
5 Replies
Steven_L_Intel1
Employee
448 Views

You can't share pointers to deferred-shape arrays in COMMON. I think the following modification would work, though.

    MODULE ARRAYS_MOD
    USE, INTRINSIC :: ISO_C_BINDING
    TYPE(C_PTR) :: P_IAR1, P_IAR2
    COMMON /MYARRS/ P_IAR1, P_IAR2
    BIND(C) :: /MYARRS/
    INTEGER, DIMENSION(:), POINTER :: IAR1
    INTEGER, DIMENSION(:), POINTER :: IAR2
    END MODULE ARRAYS_MOD
C------------------------------------------------
    SUBROUTINE ALLOC_ARRAYS
    USE ARRAYS_MOD
    INTEGER I
C--------
    ALLOCATE(IAR1(100),IAR2(100))
    P_IAR1 = C_LOC(IAR1)
    P_IAR2 = C_LOC(IAR2)
    DO I = 1,100
        IAR1(I) = I*12
        IAR2(I) = I*10
    END DO
C--------
    END
C------------------------------------------------
    SUBROUTINE DEALLOC_ARRAYS
    USE ARRAYS_MOD
C--------
    DEALLOCATE(IAR1,IAR2)
C--------
    END

Do keep in mind that Fortran arrays are 1-origin and C arrays are 0-origin.

0 Kudos
andrey_i_1
Beginner
447 Views

Thanks you much, it works!

Just one more question – this code at my system works if I only comment the string

BIND(C) :: /MYARRS/

Without this change both pointers in C code are equal to zero. Do you have any idea why?

0 Kudos
IanH
Honored Contributor II
447 Views

If you still have the same C code - the default binding label in Fortran with BIND(C) is a lower case variant of the Fortran name.  Either rename the structure object in C to the lower case variant (i.e. `struct for_arrays MYARRS;` goes to `struct for_arrays myarrs;` ) or add the NAME specifier to the BIND statement to get explicit about the C name for the common block (`BIND(C, NAME='MYARRS') :: /MYARRS/`).

(I can never remember whether the Fortran default for BIND(C) is upper or lower case, so I am always explicit about the binding label.)

 

0 Kudos
andrey_i_1
Beginner
447 Views

Everything works fine, thank you again!

0 Kudos
Steven_L_Intel1
Employee
447 Views

Thanks, Ian, I forgot about the downcasing.

0 Kudos
Reply