- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I cannot figure out, why I am not able to pass len argument correctly into c function from fortran (gfortran + gcc handle this code without any obvious problem)
simple C function
#include <stdint.h>
#include <stddef.h>
#include <stdio.h>
int32_t test (char* key, size_t len)
{
int32_t hash = 666;
printf("c key %s\n", key);
printf("c len %u\n", len); // expected 2
printf("c hash = %u\n", hash);
return hash;
}
Fortran program
!-----------------------------------------------------------------------
!Module interface_module
!-----------------------------------------------------------------------
module interface_module
implicit none
interface
function test(key, length) result(hash) bind(c, name="test")
use iso_c_binding
character(kind=c_char),dimension(*) :: key
integer(c_size_t), value :: length
integer(c_int32_t) :: hash
end function test
end interface
abstract interface
function function_hash_template(key, length)
use iso_c_binding
character(kind=c_char),dimension(*) :: key
integer(c_size_t), value :: length
integer(c_int32_t) :: function_hash_template
end function function_hash_template
end interface
contains
function test_wrap(text) result(hash)
use iso_fortran_env
implicit none
character(len=*),intent(in) :: text
integer(int32) :: hash
procedure(function_hash_template), pointer :: fun
fun => test
hash = int(hash_wrap(text, fun), int32)
end function test_wrap
!-----------------------------------------------------------------------
!Function
!-----------------------------------------------------------------------
function hash_wrap(text, fun) result(hash)
use iso_c_binding
implicit none
character (len=*), target, intent(in) :: text
procedure(function_hash_template), pointer :: fun
integer(c_int32_t) :: hash
character(kind=c_char), dimension(len_trim(text)+1) :: text_c
integer(c_size_t) :: length
text_c = f_to_c_string(text) ! convert to c string for compatibility
length = len_trim(text) + 1
write(*,*) "hash_wrap, length = ", length
hash = fun(text_c,length)
end function hash_wrap
pure function f_to_c_string (f_string) result (c_string)
use, intrinsic :: iso_c_binding, only: c_char, c_null_char
implicit none
character(len=*), intent(in) :: f_string
character(len=1,kind=c_char), dimension(len_trim(f_string)+1) :: c_string
integer :: n, i
n = len_trim(f_string)
do i = 1, n
c_string(i) = f_string(i:i)
end do
c_string(n + 1) = c_null_char
end function f_to_c_string
end module interface_module
!-----------------------------------------------------------------------
!Main program test_main
!-----------------------------------------------------------------------
program test_main
use interface_module
implicit none
write(*,*) test_wrap("1")
end program test_main
Instead of expected len = 2 I am getting always some uninitialized random len value in c function
./test_size_t_ifort_f.x
hash_wrap, length = 2
c key 1
c len 2977349904
c hash = 666
666
ifort --version
ifort (IFORT) 16.0.2 20160204
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hmm. I will take a look at this in the morning. At first glance I think the problem is you're missing bind(C) on function_hash_template. This will change the way length is passed.
Link Copied
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hmm. I will take a look at this in the morning. At first glance I think the problem is you're missing bind(C) on function_hash_template. This will change the way length is passed.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Thank you, Steve.
bind(c) solves it indeed, I was a bit confused by the "abstract interface" of the function.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Glad to hear it, though your saying gcc/gfortran accepted this suggests a bug in gfortran. Actually, the original code would have "worked" in some earlier versions of ifort as we had a bug in how we interpreted the VALUE attribute for non-bind(C) routines. We made the correct (standard-conforming) behavior the default in version 16.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
my gcc does warn about the discrepancy between %u and size_t (when -Wall is set, same for Intel C, which also warns about %u and int32_t). %zu and %d are accepted without warning, but the thing still hangs at run time when using gfortran.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
For reference, here's the main issue at hand.
The Fortran standard specifies different behavior for the VALUE attribute depending on whether the procedure being declared is "interoperable" (has BIND(C)) or not. Note that this is NOT our !DEC$ ATTRIBUTES VALUE extension.
For an interoperable procedure, VALUE means pass-by-value. The actual words in the standard are "interoperable with the corresponding formal parameter of the type" (and not of a pointer type.)
For a non-interoperable procedure, one without BIND(C), VALUE causes a writable, temporary copy of the argument to be passed by reference. So in zmi007's case, the call through the procedure pointer, defined with an interface that did not have BIND(C), caused the address of a copy of "length" to be passed. The C routine interpreted the address as the length itself, which was wrong. Adding BIND(C) to the procedure pointer's interface corrects this.
When ifort first implemented the F2003 C interoperability features we got this wrong, and always treated the Fortran standard VALUE attribute the same as !DEC$ ATTRIBUTES VALUE. In version 15 we added -assume std_value to specify the standard behavior for non-interoperable procedures, and in version 16 turned this on by default. Most of the time, VALUE is used in conjunction with BIND(C) so we didn't see a lot of issues with this change, but there were some.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
- Subscribe to RSS Feed
- Mark Topic as New
- Mark Topic as Read
- Float this Topic for Current User
- Bookmark
- Subscribe
- Printer Friendly Page