Reputation: 2971
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
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
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