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

Request for help: iso_c_binding with C calling Fortran with char[] argument

Transpire
Beginner
2,475 Views

Hi,

I'm new to using iso_c_binding and I'm having trouble figuring out the proper way to have a C main code call a F90 subroutine when the subroutine has a char[] argument. I am hopeful that someone on this forum can provide a short example or show me how my code is wrong. Here's what I have:

// main.cpp
#include
#include

// prototype for fortran subroutine
extern "C" void bar_ftn ( int flag_len, char* flag );

int main ( int /* argc */, char** /* argv[] */ )
{
char ctext[]="helloworld abcdefghijklmnopqrstuvwxyz abcdefghijklmnopqrstuvwxyz";
int ctext_len=sizeof(ctext);

// Call the Fortran
bar_ftn( ctext_len, ctext );

return 0;
}


!! Fortran code
subroutine bar_ftn ( len_input_file, input_file ) bind( c )

use, intrinsic :: iso_c_binding, only : c_int
implicit none

! Dummy arguments
integer(c_int), value, intent(in) :: len_input_file
character(len=1), intent(in) :: input_file(len_input_file)

! Local declarations (copy c char array into fortran character)
character(len=len_input_file) :: infile
integer :: i

print *, "in bar_ftn"
print *, len_input_file
do i=1,len_input_file
print *, i, input_file(i)(1:1)
! infile(i:i) = input_file(i)(1:1)
end do

end subroutine bar_ftn

This code compiles fine and runs correctly (I think) in both Debug and Release. However, when I add the /check:all flag to the Debug version, I encounter the error:

forrtl: severe (408): fort: (18): Dummy character variable 'INPUT_FILE' has length 1 which is greater then actual variable length 0

If I shorten the char[] down to 5-6 characters, the code runs correctly. What is going on here? Am I using the wrong data types when passing the char[] to the Fortran code? Can someone point me to a good example of passing strings from C to Fortran?

BTW - I am using Visual Studio 2008 SP1 and Intel Visual Fortran for Windows 11.1.035.

-kt


0 Kudos
1 Solution
IanH
Honored Contributor III
2,475 Views
Your character variables should be KIND=C_CHAR, but that's probably a technicality. I can't spot anything amiss and, rather suspiciously, it all works as expected under 11.0.074. Maybe there's something I'm missing, but I reckon you've found a problem with that diagnostic under 11.1.35.

An alternative is to take the argument as a "TYPE(C_PTR), INTENT(IN), VALUE :: ptr" and then call C_F_POINTER to associate that C_PTR with a "CHARACTER(KIND=C_CHAR), POINTER :: input_file(:)" variable, using the length that you already pass. That might avoid the diagnostic?


View solution in original post

0 Kudos
10 Replies
IanH
Honored Contributor III
2,476 Views
Your character variables should be KIND=C_CHAR, but that's probably a technicality. I can't spot anything amiss and, rather suspiciously, it all works as expected under 11.0.074. Maybe there's something I'm missing, but I reckon you've found a problem with that diagnostic under 11.1.35.

An alternative is to take the argument as a "TYPE(C_PTR), INTENT(IN), VALUE :: ptr" and then call C_F_POINTER to associate that C_PTR with a "CHARACTER(KIND=C_CHAR), POINTER :: input_file(:)" variable, using the length that you already pass. That might avoid the diagnostic?


0 Kudos
Steven_L_Intel1
Employee
2,475 Views
I know there's a problem where the compiler improperly looks for a passed character length when BIND(C) is used. That may be the issue here, but I would not expect it to be different in 11.0. I'll take a look at this tomorrow.
0 Kudos
Steven_L_Intel1
Employee
2,475 Views
I have escalated this, the issue ID is DPD200137803. The workaround is to remove the (1:1) from your references - they aren't needed anyway. The problem appears to be that the bounds checking code is incorrectly looking for a passed character length for a BIND(C) routine.
0 Kudos
Transpire
Beginner
2,475 Views
Hi Steve,

Thanks for looking into this problem. While your suggestion of removing the (1:1) did eliminate the failure in my sample code, this change did not work in my real code. ifort was still flagging the variable as having out-of-bounds when passed to a subroutine.

I also implemented IanH's suggested approach and found it to be a suitable work-around. It took me some time to get everything working because I have many character variables in my code, including some arrays of character strings that needed to be converted to this alternate approach. Using IanH's approach, I convert the type(c_ptr) to character(kind=c_char) via a call to c_f_pointer and then I convert to character(len=len_input_file) fchar using the letter-by-letter copy shown in my sample code. This works great in the current subroutine, but when the fchar is passed to another subroutine it looses knowledge of its size (defaults to len=1). To fix this side effect, I had to pass the character lengths to my subroutines and manually set the character(len=len_input_file) instead of relying on character(len=*).

Again - thank you for responding.

-kt

FWIW - Here is my updated sample code:

!! Fortran code
subroutine bar_ftn ( len_input_file, ptr_input_file ) bind( c )

use, intrinsic :: iso_c_binding, only : c_int, c_ptr, c_char, &
c_associated, c_f_pointer
implicit none

! Dummy arguments
integer(c_int), value, intent(in) :: len_input_file
type(c_ptr), intent(in), value :: ptr_input_file

! Local declarations (copy c char array into fortran character)
character(kind=c_char), pointer :: input_file(:)
character(len=len_input_file) :: infile_fchar
character(c_char), dimension(1), save, target :: dummy_string="?"
integer :: i

if( c_associated(ptr_input_file) ) then
call c_f_pointer(ptr_input_file, input_file, [len_input_file])
else
! To avoid segfaults, associate FPTR with a dummy target:
input_file => dummy_string
endif

do i=1,len_input_file
infile_fchar(i:i) = input_file(i)(1:1)
end do

print *, "infile_fchar = ", infile_fchar

end subroutine bar_ftn

0 Kudos
Transpire
Beginner
2,475 Views
I just installed 11.1.038. It doesn't appear that the bug fix made it into the 038 release. I'm continuing to see the same errors. My work around continues to work (but it breaks my Linux Pathscale F90 builds).

0 Kudos
Steven_L_Intel1
Employee
2,475 Views
No, the 038 release was already built. I'm hoping it will be fixed for the next update in August.
0 Kudos
TheClassic
Beginner
2,475 Views
I have escalated this, the issue ID is DPD200137803. The workaround is to remove the (1:1) from your references - they aren't needed anyway. The problem appears to be that the bounds checking code is incorrectly looking for a passed character length for a BIND(C) routine.

I think I might be experiencing the same problem, but I'm not sure if the problem is the compiler or me.
I am using 10.1.4161.2005

I call a fortan function from c++:

int iErr = m_pSetupDebugFn(lDebugFile, (char*)diagFilename.c_str(), diagFilenameSize, (char*)voidFilename.c_str(), voidFilenameSize);

integer(c_int) function SetupDebugFile( debugflag,
& debugfile, debugfileLen, voidfile, voidfileLen)
& bind(C,name='SETUPDEBUGFILE')
& RESULT (ierr)
!MS$ATTRIBUTES DLLEXPORT :: SETUPDEBUGFILE

The compiler adds two additional parameters for the lengths of the strings. My understanding is that it isn't supposed to pass these extra parameters when BIND(C) is used. Am I correct? Will this be fixed soon?
0 Kudos
Steven_L_Intel1
Employee
2,475 Views

You are correct. This is, I believe, fixed in 11.1.048 (11.1 Update 2)
0 Kudos
TheClassic
Beginner
2,475 Views

You are correct. This is, I believe, fixed in 11.1.048 (11.1 Update 2)
Any hope of this fix being pushed into a 10.1 release?
0 Kudos
Steven_L_Intel1
Employee
2,475 Views
None whatsoever. Not even 11.0.
0 Kudos
Reply