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

qsort and derived types or characters

rwg
Novice
849 Views
Today I had some trouble calling qsort with derived types or characters.
Because qsort is a c-function the different calling conventions have to be considerd.
Here is my solution. If someone knows a better one please let me know.
[bash]      MODULE TEST__MOD
       TYPE T_DAT
        CHARACTER(16) NAME
        CHARACTER(24) DESC
        INTEGER       IHND
       ENDTYPE T_DAT
      ENDMODULE TEST__MOD
      
      
      PROGRAM TESTPRJ_FORTRAN
      USE TEST__MOD
      USE IFPORT
      INTERFACE
        SUBROUTINE QSORT_DAT( ARRAY, LEN, ISIZE, COMPDAT )
        USE TEST__MOD
      !DEC$ ATTRIBUTES DEFAULT,DECORATE,ALIAS:'QSORT' ::  QSORT_DAT
           INTEGER LEN, ISIZE
! TYPE (T_DAT),ALLOCATABLE:: ARRAY(:)fails because FORTRAN will pass an array descriptor to C
           TYPE (T_DAT) ARRAY(*)
           INTEGER(2), EXTERNAL :: COMPDAT
        END SUBROUTINE
      END INTERFACE
      INTEGER LEN
      INTEGER ISIZE
      INTEGER(2),EXTERNAL:: COMPDAT
      TYPE (T_DAT),ALLOCATABLE:: DAT(:)
!      
      ALLOCATE(DAT(26))
      DO I=1,26
       DAT(I)%NAME=CHAR(ICHAR('Z')-I+1)
       DAT(I)%DESC="Descrpition"
       DAT(I)%IHND=0
      ENDDO
      ISIZE = SIZEOF(DAT(1))    !get size of each array element
      LEN=SIZE(DAT)             !get number ov array elements
      CALL QSORT_DAT(DAT, LEN, ISIZE, COMPDAT)
      DO I=1,LEN
       WRITE(*,*) DAT(I)%NAME
      ENDDO
      READ(*,*) LEN
      END PROGRAM TESTPRJ_FORTRAN



      INTEGER(2) FUNCTION COMPDAT(DAT1,DAT2)
! Following DECs are required because this function is called from C
! If DAT1 and DAT2 are characters this is also required, but be careful: DAT1
! and DAT2 must be declared with fixed length because the length of DAT1 and DAT2
! will not be passed!
!DEC$ ATTRIBUTES C,ALIAS:'_COMPDAT'::COMPDAT
!DEC$ ATTRIBUTES REFERENCE::DAT1
!DEC$ ATTRIBUTES REFERENCE::DAT2
      USE TEST__MOD
      TYPE(T_DAT) DAT1
      TYPE(T_DAT) DAT2
      IF(DAT1%NAME.LT.DAT2%NAME) THEN
       COMPDAT=-1
      ELSEIF(DAT1%NAME.EQ.DAT2%NAME) THEN
       COMPDAT=0
      ELSE
       COMPDAT=1
      ENDIF
      ENDFUNCTION COMPDAT
[/bash]
0 Kudos
2 Replies
mecej4
Honored Contributor III
849 Views
The most portable way of mingling C and Fortran would be to use the F2003 C-interoperability features.

You have, however, chosen the older way, which requires you to know the calling conventions of C.

A C routine such as qsort from libc has to be called using C-conventions; in particular, scalars are passed by value.

These changes will make your code run on Linux. There are many other ways, and this is just one.

1. Change INTEGER(2) to INTEGER throughout.

2. Use correct aliases for your platform. For Linux:

!DEC$ ATTRIBUTES DEFAULT,DECORATE,ALIAS:'qsort' :: QSORT_DAT
and
!DEC$ ATTRIBUTES C,ALIAS:'compdat_'::COMPDAT

3. Pass scalars by value:

CALL QSORT_DAT(DAT, %val(LEN), %val(ISIZE), COMPDAT)

0 Kudos
TimP
Honored Contributor III
850 Views
There is also a QSORT provided in the IFPORT library.
0 Kudos
Reply