Intel® Fortran Compiler
Build applications that can scale for the future with optimized code designed for Intel® Xeon® and compatible processors.
Announcements
FPGA community forums and blogs on community.intel.com are migrating to the new Altera Community and are read-only. For urgent support needs during this transition, please visit the FPGA Design Resources page or contact an Altera Authorized Distributor.
29285 Discussions

Mixed Language - C unsigned char return

Keith_Stewart
Beginner
769 Views

I have been trying to get returns from a a C sub, and seem to be going around in circles... I have tried IVF samples, suggestions from IVF forums and that I have similarly used before now, all to no avail.  Any assistance/guidance would be appreciated.

The C routine:

Syntax

int _stdcall Data_Read(
   unsigned char *pBuffer,
   int iOffset,
   int iBytesToRead,
   int *pBytesRead,
   int iFlags
);

Parameters

  • [out] pBuffer - pointer to the buffer that should receive the data read.
  • [in] iOffset - the index of the first byte to read. Indices start at zero. If this value is negative, the function will treat it as if it were zero, and read from the start of the Data.
  • [in] iBytesToRead - the number of bytes to read. If this value is negative, the function will return an error.
  • [out, optional] pBytesRead - pointer to a variable that receives the number of bytes read.
  • [in] iFlags - set this parameter to GET_Data_SIZE (1, or BIT0 set) to get the total size of the Data in the variable pointed to by pBytesRead. The buffer that pBuffer points to remains unmodified. Pass zero to perform a read with no special behaviour.

My Fortran module:

      interface
        function Data_READ(Ret_Str, Int1, Int2, Data_Bytes, Int3)
          !DEC$ ATTRIBUTES STDCALL,DECORATE,ALIAS:"Data_Read" :: Data_READ
          integer :: Data_READ
          character*(*) :: Ret_Str
          integer :: Int1, Int2, Data_Bytes, Int3
          !DEC$ ATTRIBUTES REFERENCE :: Ret_Str, Int1, Int2, Data_Bytes, Int3
        end function Data_READ
      end interface

My Fortran routine:

      use, intrinsic :: iso_c_binding, only: c_int
      implicit none
      character(len=50) :: Ret_Str
      integer :: iRet
      integer(C_int) :: iOut_1, iOut_2, Data_Bytes, iOut_3
      iOut_1 = 0 ; iOut_2 = 50 ; iOut_3 = 0
      iRet = Data_Read(Ret_Str, iOut_1, iOut_2, Data_Bytes, iOut_3)

The data in pbuffer (from the C sub) can be up to 512 bytes... I currently have 34 characters stored in the area that the C sub reads, and am trying to get those into my program.

I have other routines that read similarly read strings from C routines, but I cannot figure what I have done wrong or am missing (I know something is not right/missing, but not what nor where).  At present the returns I get are 0 for iRet (0 indicates success), 0 for Data_Bytes, and Ret_Str is blank.

 

 

0 Kudos
4 Replies
IanH
Honored Contributor III
769 Views

Your Fortran specifies Int1, Int2 and Int3 as pass by reference - when the C declaration says they are by value.

It is also possible that the calling conventions for the assumed length character string trip you up (this can change with compile options).

For what its worth, if I had to write a Fortran interface for this C function (guessing a little as to the behaviour beyond what your documentation provides and calling "bytes" INTEGER(C_SIGNED_CHAR)) I'd do it something like:
[fortran]

MODULE MakeCallingDataReadFromFortranEasy
  IMPLICIT NONE
  PRIVATE
 
  PUBLIC :: GetTotalSizeOfData
  PUBLIC :: ReadSomeData
  PUBLIC :: ReadItAllAtOnce
 
  INTERFACE
    FUNCTION Data_Read(pBuffer, iOffset, iBytesToRead, pBytesRead, iFlags)
      USE, INTRINSIC :: ISO_C_BINDING, ONLY: C_INT, C_PTR
      IMPLICIT NONE
      TYPE(C_PTR), INTENT(IN) :: pBuffer
      INTEGER(C_INT), INTENT(IN) :: iOffset
      INTEGER(C_INT), INTENT(IN) :: iBytesToRead
      INTEGER(C_INT), INTENT(OUT) :: pBytesRead
      !DEC$ ATTRIBUTES REFERENCE :: pBytesRead
      INTEGER(C_INT), INTENT(IN) :: iFlags
      INTEGER(C_INT) :: Data_Read
      !DEC$ ATTRIBUTES STDCALL :: Data_Read
      !DEC$ ATTRIBUTES ALIAS:'Data_Read' :: Data_Read
      !DEC$ ATTRIBUTES DECORATE :: Data_Read
    END FUNCTION Data_Read
  END INTERFACE
CONTAINS
  SUBROUTINE GetTotalSizeOfData(total_size, result)
    USE, INTRINSIC :: ISO_C_BINDING, ONLY: C_INT, C_LOC, C_NULL_PTR
    INTEGER(C_INT), INTENT(OUT) :: total_size
    INTEGER(C_INT), INTENT(OUT) :: result
    !****
    ! Assume that buffer
    result = Data_Read( C_NULL_PTR, 0_C_INT, 0_C_INT, total_size,  &
        1_C_INT )
  END SUBROUTINE GetTotalSizeOfData
 
  SUBROUTINE ReadSomeData(data, offset, bytes_to_read, bytes_read, result)
    USE, INTRINSIC :: ISO_C_BINDING, ONLY: C_INT, C_LOC, C_SIGNED_CHAR
    INTEGER(C_SIGNED_CHAR), INTENT(OUT), TARGET :: data(*)
    INTEGER(C_INT), INTENT(IN) :: offset
    INTEGER(C_INT), INTENT(IN) :: bytes_to_read
    INTEGER(C_INT), INTENT(OUT) :: bytes_read
    INTEGER(C_INT), INTENT(OUT) :: result
    !****
    result = Data_Read( C_LOC(data), offset, bytes_to_read, bytes_read,  &
        0_C_INT )
  END SUBROUTINE ReadSomeData
 
  SUBROUTINE ReadItAllAtOnce(data, result)
    USE, INTRINSIC :: ISO_C_BINDING, ONLY: C_INT, C_LOC, C_SIGNED_CHAR
    INTEGER(C_SIGNED_CHAR), INTENT(OUT), ALLOCATABLE :: data(:)
    INTEGER(C_INT), INTENT(OUT) :: result
    !----
    INTEGER(C_INT) :: total_size
    INTEGER(C_INT) :: bytes_read
    !****
    CALL GetTotalSizeOfData(total_size, result)
    IF (result /= 0) RETURN
    
    ALLOCATE(data(total_size))
    CALL ReadSomeData(data, 0_C_INT, total_size, bytes_read)
    IF (result /= 0) RETURN
    
    IF (total_size /= bytes_read)  &
        ERROR STOP 'Total size isn''t bytes_read!'
  END SUBROUTINE ReadItAllAtOnce
END MODULE MakeCallingDataReadFromFortranEasy

[/fortran]

(But I wouldn't double space things...)

0 Kudos
TimP
Honored Contributor III
769 Views

 

ian has dropped your stdcall specification, with good reason.

0 Kudos
IanH
Honored Contributor III
769 Views

Tim Prince wrote:

 

ian has dropped your stdcall specification, with good reason.

I agree, but I didn't mean to (and I don't think I did).

0 Kudos
Keith_Stewart
Beginner
769 Views

Many thanks Ian - I transposed parts of your suggested code into my module and routine, and it now works - I can return the read bytes and data area content exactly as I had hoped to.

I never would have got it myself as I have not found anything on how to address unsigned/signed characters to a buffer - many thanks again.

0 Kudos
Reply