To: J3 11-132r2 From: R. Bader/Toon Moene Subject: examples for use of the CFI_associate() function Date: 2011 February 16 References: N1838 INTRODUCTION: The function CFI_associate() is designed for two usage patterns: (1) to modify C descriptors for assumed shape entities so as to allow production of array slices / subobjects or create assumed-shape entities inside C, (2) to perform something much (but not fully?) like pointer association for C descriptors for Fortran POINTERs. This paper provides some examples for the use of this function (hopefully making the correct assumptions about its semantics). EDITS to N1838: [21:17+] Add line "A.2.1 Example for array processing using the C descriptor" [21:32+] At the end of A.2. add "A.2.2 Example for creating an array slice in C Given the Fortran interface for a function which is intended to set every second array element, beginning with the first one, to some provided value, interface subroutine set_odd(int_array, val) bind(c) use, intrinsic :: iso_c_binding, only : c_int integer(c_int) :: int_array(:) integer(c_int), value :: val end subroutine end interface the implementation in C reads #include "ISO_Fortran_binding.h" void set_odd(CFI_cdesc_t *int_array, int val) { CFI_dim_t dims[1]; CFI_CDESC_T(1) array; int status; /* the following is equivalent to saying int_array(1::2) in Fortran */ dims[0]->lower_bound = 0; dims[0]->extent = (int_array->dim[0].extent + 1)/2; dims[0]->sm = 2*int_array->dim[0].sm; /* Update the descriptor with the new information */ status = CFI_establish_cdesc(&array, int_array->base_addr, CFI_attribute_assumed, int_array->type, int_array->elem_len, /* rank */ 1, dims); set_all(array, val); /* here one could make use of int_array and access all its data */ } A copy of the incoming descriptor is created because the call to CFI_establish_cdesc() irreversibly modifies the descriptor {\footnote At least the extent and sm members of int_array->dim[0] will be modified: sm will be doubled, and the value of the extent member will be changed to (extent + 1)/2. }. <> Without such a copy, it would not be possible to access all data of the incoming descriptor after the invocation of CFI_establish_cdesc(), which may be a problem for the remaining part of the implementation, or - after the call site - for a C function which invokes set_odd() (see below). The function set_odd() implements its functionality in terms of a Fortran subprogram subroutine set_all(int_array, val) bind(c) integer(c_int) :: int_array(:) integer(c_int), value :: val int_array = val end subroutine Let invocation of set_odd() from a Fortran program be done as follows: integer(c_int) :: d(5) d = (/ 1, 2, 3, 4, 5 /) call set_odd(d, -1) write(*, *) d Then, the program will print -1 2 -1 4 -1 During execution of the subprogram set_all(), its dummy object int_array would appear to be an array of size 3 with lower bound 1 and upper bound 3. It is also possible to invoke set_odd() from C. However, it is the C programmer's responsibility to make sure that all members of the descriptor have the correct value on entry to the function. Inserting additional checking into the function's implementation could alleviate this problem. /* necessary includes omitted */ #define ARRAY_SIZE 5 CFI_CDESC_T(1) d; CFI_dim_t dims[1]; void *base; int i, status; base = malloc(ARRAY_SIZE*sizeof(int)); dims[0]->lower_bound = 0; dims[0]->extent = ARRAY_SIZE; dims[0]->sm = sizeof(int); /* different from CFI_allocate, stride must be specified here */ status = CFI_establish_cdesc(&d, base, CFI_attribute_assumed, CFI_type_int, sizeof(int), /* rank * / 1, dims); set_odd(d, -1); for (i=0; iattribute == CFI_attribute_pointer && ip->rank == 0) { CFI_establish_cdesc(ip, &y, CFI_attribute_pointer, CFI_type_int, sizeof(int), /* rank */ 0, /* dim */ NULL); } } The following Fortran code use, intrinsic :: iso_c_binding interface subroutine change_target(ip) bind(c) import :: c_int integer(c_int), pointer :: ip end subroutine end interface integer(c_int), target :: it = 1 integer(c_int), pointer :: it_ptr it_ptr => it write(*,*) it_ptr call change_target(it_ptr) write(*,*) it_ptr will then print 1 2" <>