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

Passing Strings to FORTRAN DLL by Reference

saquatch
Beginner
1,118 Views

Below is a simple string sub exposed as a DLL method.  Can someone comment on my questions?  Thanks!

 

ARG comes in as a reference to an array of chars due to being passed by reference.   Correct?

When I look at ARG's value in VS Watch it looks like an array of chars, not a string: VS Watch shows its type as char[250]* not char[250].  What is the difference and why would there be one at this point inside FORTRAN code?

If I pass a char array longer than 250, will it get truncated to 250 chars or will there be an overflow?

When ARG is assigned to LOCAL, LOCAL get its values, but LOCAL displays as a char[250] not as char[250]*.  This I would expect, but I would expect it from ARG too.

But, LOCAL does show as a fixed length char with the usual padding out to 250 chars: it looks fixed length less than 250 chars, no padding.  Why is it not padded after being assigned to ARG?

 

SUBROUTINE MYSUB(ARG)
!DEC$ ATTRIBUTES DLLEXPORT :: MYSUB
!DEC$ ATTRIBUTES ALIAS : 'MYSUB' :: MYSUB
!DEC$ ATTRIBUTES C, REFERENCE

CHARACTER*250 ARG
CHARACTER*250 LOCAL

LOCAL= ARG


RETURN
END

 

0 Kudos
5 Replies
jimdempseyatthecove
Honored Contributor III
1,110 Views

The ARG will assumed to be a character(len=250) buffer.

Note, Fortran does not use NULL terminated strings.

Your C/C++/C#/?? program will likely pass in a NULL terminated string.

Therefor, you should parse the input (ARG) for NULL, 

 

iNULL = INDEX(ARG, ACHAR(0))

select case(iNULL)

case(0)

  LOCAL = ARG ! NULL not found, length of incoming string .ge. buffer

case(1)

  LOCAL = ' ' ! NULL string

case default

  LOCAL = ARG(1:iNULL-1) ! copy sans NULL, then space fille

end select

 

If (when) the incoming string is longer than the buffer, data will be truncated (the reference contains the data but it is not accessible beyond the size (len=nn) specified. You can specify ARG with an inordinately large length, or at least 1 larger than your API specifies. Then if NULL not found, you can report string too long.

 

Jim Dempsey

0 Kudos
saquatch
Beginner
1,103 Views

Thanks so much Jim.

 

C# client yes.  ARG is a char[250] in C#.  If I pad in C# ARG to 250 spaces, LOCAL will be padded in FORTRAN.  My conclusion is LOCAL=ARG stop at the first NULL it finds in ARG.  No need to parse for NULL.

 

But why does the assignment not pad LOCAL out to 250 regardless as it does if you assign a scaler string to it: LOCAL="Test"

 

 

0 Kudos
jimdempseyatthecove
Honored Contributor III
1,069 Views
program ShowNULL
    implicit none
    character*250 :: arg
    character*250 :: s1
   
    arg = "asdf"        ! padds remainder of arg with spaces
    print *,len_trim(arg)
    arg(50:50) = achar(0) ! inserts NULL at arg(50)
    print *,len_trim(arg)
    s1 = trim(arg) // "foo"
    print *, s1
end program ShowNULL
Output:
           4
          50
 asdf                                              foo

Note, the NULL is treated as non-blank character.

Therefore your statement:

My conclusion is LOCAL=ARG stop at the first NULL it finds in ARG.  No need to parse for NULL.

is .FALSE.

 

Jim Dempsey

0 Kudos
FortranFan
Honored Contributor III
1,090 Views

@saquatch ,

If I recall correctly the compilation directive semantics (!DEC$) per Intel Fortran (Digital Fortran previously), you need to specify the REFERENCE attribute explicitly for each received argument of CHARACTER type i.e., ARG in your case.  But I may be wrong as I avoid using these directives like the plague, nonetheless I suggest you try out the following:

SUBROUTINE MYSUB(ARG)
!DEC$ ATTRIBUTES DLLEXPORT :: MYSUB
!DEC$ ATTRIBUTES ALIAS : 'MYSUB' :: MYSUB
!DEC$ ATTRIBUTES C, REFERENCE
!DEC$ ATTRIBUTES REFERENCE :: ARG

   CHARACTER*250 ARG
   CHARACTER*250 LOCAL

   LOCAL= ARG
   
   RETURN

END SUBROUTINE
0 Kudos
FortranFan
Honored Contributor III
1,088 Views

@saquatch ,

Separately if you're interested in a standard-based way to interoperate your Fortran code with Microsoft's managed memory .NET system (C#) via the processor that serves as a common companion to both Fortran and .NET i.e., Microsoft C/C++ processor, then see the example below, a recent thread at this forum:

https://community.intel.com/t5/Intel-Fortran-Compiler/Integrate-C-DLL-in-Fortran-Code/m-p/1411688/highlight/true#M162662

 

The above example has a C++ caller but that does not matter to the Fortran side of things.  The exact same Fortran code can work with a C# caller.  And it has a couple of instances of string passing. 

0 Kudos
Reply