- 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