On Tuesday, February 7, 2017 at 6:03:51 AM UTC-5,
edmondo.g...@gmail.com wrote:
> Dear all, is this standard conforming:
>
> integer, pointer :: a(:)
> type(C_PTR) :: ptr
> integer, pointer :: b(:)
>
> allocate(a(5))
> ptr = c_loc(a)
> call c_f_pointer(ptr,b,[5])
> deallocate(b)
>
> The aim is to pass back to a C routine a pointer allocated in Fortran, and then deallocate it in another Fortran routine ..
> .. I'm writing some small examples on Fortran calling C
My hunch is for the code you show in the original post, as long as the actual arguments to C_LOC and C_F_POINTER procedures meet the requirements stated in the standard, the code is standard-conforming. For example, the standard stipulates for C_LOC(X), "Argument. X shall have either the POINTER or TARGET attribute. It shall not be a coindexed object. It shall either be a variable with interoperable type and kind type parameters, or be a scalar, nonpolymorphic variable with no length type parameters. If it is allocatable, it shall be allocated. If it is a pointer, it shall be associated. If it is an array, it shall be contiguous and have nonzero size. It shall not be a zero-length string."
But as to whether your approach is "safe" and a "good coding practice" - given the usual caveats about working with pointers - is a matter outside the scope of the standard, I think.
Re: your objectives such as "writing some small examples on Fortran calling C", unless your scope is restricted to an arbitray compiler (and a version) that fails yet to support enhanced interoperability with C feature extensions to the standard, then I suggest you look into the capabilities introduced with Fortran 2015 and which are supported by compilers such as Intel Fortran, IBM, etc.
For the case you show in the original post of "C is calling Fortran", my recommended approach is to employ the procedures of CFI_allocate, CFI_establish, and CFI_deallocate described in "ISO_Fortran_binding.h" on the C side as the new *standard* way to achieve the same goals.
Here's an example with a rank 1, floating-point array:
-- begin Fortran code --
module m
use, intrinsic :: iso_c_binding, only : c_double, c_int
implicit none
contains
subroutine f_alloc(Array, ErrorCode) bind(C, name="f_alloc")
!.. Argument list
real(c_double), allocatable, intent(out) :: Array(:)
integer(c_int), intent(inout) :: ErrorCode
!.. Local variables
integer :: I
allocate( Array(-3:3), stat=ErrorCode)
if (ErrorCode == 0) then
Array = [( real(I, kind=kind(Array)), I=lbound(Array,dim=1), ubound(Array,dim=1) )]
end if
return
end subroutine f_alloc
end module m
-- end Fortran code --
-- begin C code --
#include <stdio.h>
#include "ISO_Fortran_binding.h"
// Prototype for Fortran allocator
void f_alloc(CFI_cdesc_t * arr, int *irc);
int main()
{
int irc;
CFI_rank_t rank;
CFI_CDESC_T(1) field; // use CFI_CDESC_T macro in the header to declare an interoperable object with Fortran
double* d;
int i;
irc = 0;
rank = 1;
irc = CFI_establish((CFI_cdesc_t *)&field, NULL,
CFI_attribute_allocatable,
CFI_type_double, 0, rank, NULL);
if (irc == CFI_SUCCESS) {
printf("CFI_establish succeeded.\n");
}
else {
printf("CFI_establish failed: irc = %d.\n", irc);
return(irc);
}
// Call Fortran allocator
f_alloc((CFI_cdesc_t *)&field, &irc);
if (irc == 0) {
printf("f_alloc successful.\n");
d = (double *)field.base_addr;
for (i = 0; i < field.dim[0].extent; i++) {
printf("d[%d] = %f\n", field.dim[0].lower_bound+i, d[i]);
}
}
irc = CFI_deallocate((CFI_cdesc_t *)&field);
if (irc == CFI_SUCCESS) {
printf("CFI_deallocate succeeded.\n");
}
else {
printf("CFI_deallocate failed: irc = %d.\n", irc);
return(irc);
}
return 0;
}
-- end C code --
Upon execution of code compiled with Intel Fortran,
-- begin output --
CFI_establish succeeded.
f_alloc successful.
d[-3] = -3.000000
d[-2] = -2.000000
d[-1] = -1.000000
d[0] = 0.000000
d[1] = 1.000000
d[2] = 2.000000
d[3] = 3.000000
CFI_deallocate succeeded.
-- end output --