javacavaj
javacavaj

Reputation: 2971

Converting a variable length c-string to Fortran string in Visual Studio

I need to convert a C string to a Fortran string. When I debug the example code, in Visual Studio 2012 with the Intel Visual Fortran Composer XE 2013, I encounter a couple of issues:

1) I can't see the value of the deferred-length allocatable character variable (str) in the debugger.

2) Allocating this variable type causes the fCode.pdb file to lock when a break point is placed in the code. The only way to free the file is to close the handle (via Process Explorer) or close the IDE.

Am I missing something in the code? Freeing memory? Is there a cleaner way to do the conversion?

C code

int main ( void ) {

    char* cstr = "BP1000";

    c_to_f(cstr);

    return 0;
}

Fortran code

module mytest
    contains

    subroutine c_to_f(cstr)  BIND(C, name="c_to_f")
    use, intrinsic :: iso_c_binding    
    !DEC$ ATTRIBUTES DLLEXPORT :: c_to_f

    character(kind=C_CHAR, len=1), intent(IN) :: cstr(*)    
    character(:), allocatable :: str

    str = c_to_f_string(cstr)

    end subroutine c_to_f  

    function c_to_f_string(s) result(str)
      use, intrinsic :: iso_c_binding
      character(kind=C_CHAR, len=1), intent(IN) :: s(*)
      character(:), allocatable  :: str
      integer i, nchars
      i = 1
      do
         if (s(i) == c_null_char) exit
         i = i + 1
      end do
      nchars = i - 1  ! Exclude null character from Fortran string
      allocate(character(len=nchars) :: str)
      str = transfer(s(1:nchars), str)
    end function c_to_f_string

end module mytest   

Upvotes: 2

Views: 1088

Answers (2)

0xF
0xF

Reputation: 3728

It is unclear in the question how the C code would use the Fortran string?

If the string comes from a C function:

const char *getcstr(void)
{
    return "Hello!";
}

here is the complete Fortran program that calls the C function, turns the result into a Fortran string, then prints:

implicit none

interface
    function getcstr() bind(c, name="getcstr")
        use, intrinsic :: iso_c_binding
        type(c_ptr) getcstr
    end
end interface

print *, cstr2f(getcstr())

contains
    function cstr2f(s)
        use, intrinsic :: iso_c_binding
        interface
            pure function strlen(s) bind(c, name="strlen")
                use, intrinsic :: iso_c_binding
                type(c_ptr), intent(in), value :: s
                integer(c_size_t) strlen
            end
        end interface
        type(c_ptr) s
        character(kind=c_char, len=strlen(s)), pointer :: cstr2f

        call c_f_pointer(s, cstr2f)
    end
end

Upvotes: 3

cup
cup

Reputation: 8299

1) Watching variables from Fortran modules: use modulename::variablename. Are you running the debug or release version? If you are running the release version, switch on symbols in project properties. If you are running the debug version, is the .pdb in the same directory as the executable? If you're doing Fortran and C, there will be two pdb files. All DLLs and exes must be in the same directory. To achieve this automatically, change the project settings. Instead of

+ solution
  +-- C program
      +-- debug (both $IntDir and $OutDir point here)
  +-- Fortran lib
      +-- debug

Change it to

+ solution
  +-- debug (change the project output $OutDir to this place)
  +-- C program
      +-- debug ($IntDir remains here)
  +-- Fortran lib
      +-- debug ($IntDir remains here)

Also change the .pdb location to $(OutDir)$(TargetName).pdb. The default is $(IntDir)vc100.pdb (or whatever the visual studio version is times 10).

2) Re locking. The pdb files will lock whenever you add breakpoints and run. They shouldn't lock if the program is not running unless your version of VS has locked it. Have the VS SPs been applied? Also, make sure that both the C program and the Fortran program have the same calling convention. There is stdcall and cdecl. In Fortran, this is done in the project settings. It doesn't matter if no parameters are passed but when parameters are passed, make sure that both of them use the same convention.

For differences between stdcall and cdecl refer to stdcall and cdecl

Upvotes: 0

Related Questions