2

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   
0

2 Answers 2

3

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
Sign up to request clarification or add additional context in comments.

6 Comments

@francescalus Thanks for comments, revised my answer.
I have no idea how is this related to points 1 and 2 of the question. Are you suggesting that the code the OP presents is wrong? In which way? He is actually asking if he is missing something in the code. Is he?
A Fortran string is useful in Fortran, naturally. OP calls the conversion from C and discards the result.
@0xF I am trying the reproduce the results of your above code for different C return message ( instead of "Hello!" I am using "Hello_world_from_C!" ). However, Fortran always prints only first 6 characters, that is "Hello_". Does your program work for message of any length?
@Moonwalk My code was missing the "value" attribute. Fixed now, thanks!
|
0

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.