Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

deallocate a Fortran pointer through its C address

510 views
Skip to first unread message

edmondo.g...@gmail.com

unread,
Feb 7, 2017, 6:03:51 AM2/7/17
to
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 (the C is calling Fortran). From the standard it looks like that it should be possible if a and b where just scalar, it is not clear for me if the same is true if them are arrays.
By the way, gfortran compiles that without any memory leakage (checked with fsanitize=address).

I'm writing some small examples on Fortran calling C and the reverse, this is why I want to be sure it is standard conforming.

FortranFan

unread,
Feb 7, 2017, 9:33:50 AM2/7/17
to
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 --

edmondo.g...@gmail.com

unread,
Feb 7, 2017, 11:37:46 AM2/7/17
to
Thanks, FortranFan, for your example.
The 2015 C extension capabilities will be a better approach, and, as you say, a much safer one. Up to now, I have always called C from Fortran so that situation never really happened, and if it will happen I will follow your advice and use the 2015 extensions.

But I was wondering if one can get something working without Fortran 2015.

Going back to my example if a and b were scalars, then the code would be standard conforming (I think). It is stated in the standard (as found on the gfortran website) that after a call to C_F_POINTER(C_LOC(X),FPTR), where X is scalar, FPTR is "pointer associated" with X. And, if I correctly interpret the standard that means that it is equivalent to FPTR => X.In this case if X is a pointer explicitly allocated with allocate(X), then I can deallocate the memory using FPTR with deallocate(FPTR).

In the other sentence where they are speaking about the situation where X and FPTR are arrays they are just speaking of association. Does that mean something similar to FPTR => X (assuming to pass the shape of X to the shape argument, and X being contiguous, of course), or not?
I am looking at the paragraph 15.2.3.3 of the document J3/SD-007 that I found on the gfortran website.

Sorry for my, sometime, legalistic point of view, but I'm really worried to writing something that is not following the standard. I think there is a difference between something that is discouraged to use (who is going to use an implicit statement different from "implicit none") and something that is not in the standard, like the famous extension "real*4" (even though the latter may be less dangerous).

Thanks,




herrman...@gmail.com

unread,
Feb 7, 2017, 2:00:08 PM2/7/17
to
On Tuesday, February 7, 2017 at 3:03:51 AM UTC-8, 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)

As well as I understand, it isn't conforming as of F2008, though
that doesn't mean it won't work.

In addition to reading about C_F_POINTER, also read
about DEALLOCATE.

In the usual implementations of C, a pointer is just an address.
The C standard doesn't require that, but it is in most implementations.

Fortran pointers, on the other hand, have array bounds information
included. The C library has, with most implementations, someway
keep track of the length of allocated (with malloc()) data, so that
free() can do the right thing.

It is usual, but not required, to write Fortran compilers and libraries
in C, and so it should be possible to allocate, otherwise create, and
deallocate Fortran pointers in C, but there is no standard way to
do that. (At least, as far as I know, through F2008.)

It is likely that a Fortran pointer contains a C pointer, along with
bounds information, and that C_F_POINTER creates a Fortran
pointer with the C pointer inside. It is also likely that DEALLOCATE
calls the C library to deallocate such C pointer, and so it is likely
that it will do just what you want, but I don't see anything in the standard
through F2008 that specifies that it works that way.

Best is to allocate in C, pass C pointers around, and deallocate in C,
or ALLOCATE in Fortran, pass Fortran pointers around, and DEALLOCATE
in Fortran. You should, for example, be able to access a pointer in
a COMMON block, or a module variable, in another Fortran routine,
and use it accordingly.

Not so far off is using C_SIZEOF to find the length of a Fortran
pointer, and to make a byte for byte copy of it. pass that to C,
and then back to Fortran again.

I don't see anything that says that a byte for byte copy of a
Fortran pointer is guaranteed to work, but it seems likely.

> The aim is to pass back to a C routine a pointer allocated in Fortran,
> and then deallocate it in another Fortran routine (the C is calling Fortran).
> From the standard it looks like that it should be possible if a and b where
> just scalar, it is not clear for me if the same is true if them are arrays.


> By the way, gfortran compiles that without any memory leakage
> (checked with fsanitize=address).

> I'm writing some small examples on Fortran calling C and the reverse,
> this is why I want to be sure it is standard conforming.

-- glen

Richard Maine

unread,
Feb 7, 2017, 2:17:30 PM2/7/17
to
<herrman...@gmail.com> wrote:

> On Tuesday, February 7, 2017 at 3:03:51 AM UTC-8, 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)
>
> As well as I understand, it isn't conforming as of F2008, though
> that doesn't mean it won't work.

Why not? I don't see anything that it violates. The part of your post
that I elided discussed how C pointers can differ from Fortran ones.
That would certainly be relevant if the OP were trying to do either the
allocate or the deallocate in C. But he isn't.

The allocation of "a" is done by a Fortran allocate.

His b is a Fortran pointer - not a C one. The fact that C code was
involved in the process of getting it defined seem irrelevant. I see no
restriction on the order of "was C ever involved?" However it got
defined, it is, before the deallocate, a valid Fortran pointer. It is of
the right type, type parameters, and shape, and points at the whole of
the allocated object.

I'm willing to stand corrected if you can point to an actual restriction
that it violates, but I don't see one.

--
Richard Maine
email: last name at domain . net
dimnain: summer-triangle

Ian Harvey

unread,
Feb 7, 2017, 2:28:22 PM2/7/17
to
Maybe - the kind of the integer array must be interoperable - C_INT or
whatever suits your fancy. Whether default integer is interoperable is
processor dependent. If I was writing an example I would explicitly
specify the integer kind to make sure that it is interoperable.

Sort that out and you are ok.

I have seen explicit mention that the ability to connect a Fortran
pointer allocation and later deallocation, via a C address, was a design
intent of F200X. I use this all the time with non-interoperable scalar
objects.



herrman...@gmail.com

unread,
Feb 7, 2017, 2:34:07 PM2/7/17
to
On Tuesday, February 7, 2017 at 3:03:51 AM UTC-8, 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)

As I noted above, in most C implementations a pointer is just
a memory address. But the C standard is carefully written not
to require that.

In the past (before C) there have been systems that didn't do
any hardware memory protection, but depended on software.

The system would only run programs generated by a known
compiler, and that compiler would only generate object programs
that couldn't do anything bad to the system. All array references
are bounds checked. You can't download a file from the web,
or even a tape, and run it. It shouldn't be so hard to write a
Fortran compiler for a system like that, not so easy for C.

C pointers have to include at least bounds on the memory
allocated, not necessarily on individual subscripts. (Note that
it complicates Fortran assumed size arrays.)

It is interesting that Java comes close to doing that.
Within the Java language, all array accesses are bounds
checked, and references to objects tested to make
sure that they are of the appropriate class, or subclass
of the the expected class. A cast is required for object
reference assignment that could violate the rules, and a
class cast exception is issued if a reference isn't valid.

Ian Harvey

unread,
Feb 7, 2017, 2:39:22 PM2/7/17
to
...

I don't agree with this, in the general case.

Exposing a descriptor to the C code in this way is appropriate when the
C code needs to interact directly with non-trivial information that is
available in the descriptor. If that need isn't there, then you are
incurring a substantial increase in complexity in the C source for no
benefit.

Match the information provided across an interface with the information
required.

James Van Buskirk

unread,
Feb 7, 2017, 3:36:12 PM2/7/17
to
"Richard Maine" wrote in message
news:1n12ppj.ut778hwbuqp6N%nos...@see.signature...

> I'm willing to stand corrected if you can point to an actual restriction
> that it violates, but I don't see one.

I thought that code like

program test
implicit none
integer, pointer :: a(:), b(:)
allocate(a(5))
b => a(1:5)
deallocate(b)
end program test

Was invalid, and in fact ifort fails this example at run time. How does
this differ materially from the O.P.'s example?

FortranFan

unread,
Feb 7, 2017, 3:44:17 PM2/7/17
to
On Tuesday, February 7, 2017 at 2:39:22 PM UTC-5, Ian Harvey wrote:

> On 2017-02-08 01:33, FortranFan wrote:
> ..
> >
> > 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:
> ...
>
> I don't agree with this, in the general case.
>
> Exposing a descriptor to the C code in this way is appropriate when the
> C code needs to interact directly with non-trivial information that is
> available in the descriptor. ..


OP has indeed presented a specific case that involves "non-trivial" aspects: objects are to be allocated and deallocated in Fortran and the objects can be arrays, thus their rank, extent, shape, lower and upper bounds can all be important during the object consumption on the C side.

It's under such circumstances that the Fortran 2015 standard strongly suggests the solution outlined in the example above.

If these are not important, then OP and his target audience can refer to Modern Fortran Explained by Metcalf et al. and Fortran 2003 Handbook by Adams et al. for good coverage of this topic.

FortranFan

unread,
Feb 7, 2017, 4:47:26 PM2/7/17
to
On Tuesday, February 7, 2017 at 3:36:12 PM UTC-5, James Van Buskirk wrote:

> ..
>
> I thought that code like
>
> program test
> implicit none
> integer, pointer :: a(:), b(:)
> allocate(a(5))
> b => a(1:5)
> deallocate(b)
> end program test
>
> Was invalid, and in fact ifort fails this example at run time. ..


I think this code is standard-conforming too; what Intel Fortran is doing is providing the diagnostics that it is able to recognize, that the action to deallocate the anonymous target associated with b was allocated and associated with a separate object. But I don't think the processor is required to do so by the standard. Make the code a tad more complicated where pointer allocations and associations get easily masked for the Intel Fortran compiler and it will provide little help. And this holds for the code in the original post as well. And gfortran doesn't raise an exception in either of the cases.


James Van Buskirk

unread,
Feb 7, 2017, 5:38:46 PM2/7/17
to
"FortranFan" wrote in message
news:e71396c7-79fa-4801...@googlegroups.com...
I guess this is J3/04-378r1. It looks to be standard-conforming, see
http://j3-fortran.org/doc/year/04/04-378r1.txt
ftp://ftp.nag.co.uk/sc22wg5/N1801-N1850/N1805.txt

I recalled elements of the discussion, but apparently not the
result.

Richard Maine

unread,
Feb 7, 2017, 5:40:36 PM2/7/17
to
Hmm. That one is a little subtle. Indeed, I might possibly have the
interpretation of it wrong. I think there might even have once been an
interp on that sort of thing, but I can't handily find it at the moment.

Two things occur to me. Neither of these directly apply to the C
example. Both relate to the fact that a(1:5) is a slice of "a" rather
thah actually being "a". That's not the case in the OP's example, where
no slices were involved.

1. I'm not sure whether a(1:5) counts as being "the whole of" the array
"a". (I hate it when examples use "a" as a variable name because I then
have to quote it to avoid confusion with the Ensglish indefinite
article). It happens to have all of the elements, but I'm not sure
whether that is enough to count as being the whole of it.

2. a(1:5) does not have the pointer attribute. It does have the target
attribute because subobjects of targets ar ealso targets. But a
subobject of a pointer is not a pointer, even if it happens to be a
subobject that has all the elements.

Richard Maine

unread,
Feb 7, 2017, 5:57:40 PM2/7/17
to
FortranFan <pare...@gmail.com> wrote:

> I think this code is standard-conforming too; what Intel Fortran is doing
> is providing the diagnostics that it is able to recognize, that the
> action to deallocate the anonymous target associated with b was
> allocated and associated with a separate object. But I don't think the
> processor is required to do so by the standard.

I have some uncertainty as to whether or not James' example is standard
conforming. I think probably not, but I'm a little uncertain. See my
reply to him.

But the Intel compiler is not giving a warning. It is a fatal error at
run time. If the code were standard conforming, then that would be an
error in the compiler. Compilers are not allowed to refuse to run
standard conforming code because it thinks something is questionable.
They may provide warnings, but they can't refuse to run the code.

Note also that deallocating a pointer that was allocated via some other
variable is completely ordinary. That is done with pointers all the
time. I guarantee that the Intel compiler doesn't fail or warn about
that in general because if it did, I'd have noticed with many of my
codes. The problem here has nothing to do with it being some other
variable, but with the slice.

Say, I've still got that example sitting in a file handy here, so I can
directly test that instead of just saying what I'm sure to be the
case....

Yep. Change the

b => a(1:5)

to

b => a

and Intel is happy as could be with it.

Richard Maine

unread,
Feb 7, 2017, 6:08:37 PM2/7/17
to
James Van Buskirk <not_...@comcast.net> wrote:

> > > program test
> > > implicit none
> > > integer, pointer :: a(:), b(:)
> > > allocate(a(5))
> > > b => a(1:5)
> > > deallocate(b)
> > > end program test
>
> > > Was invalid, and in fact ifort fails this example at run time. ..
...
> I guess this is J3/04-378r1. It looks to be standard-conforming, see
> http://j3-fortran.org/doc/year/04/04-378r1.txt
> ftp://ftp.nag.co.uk/sc22wg5/N1801-N1850/N1805.txt
>
> I recalled elements of the discussion, but apparently not the
> result.

Ah. Ok. Those are probably the interps I thought might exist, though I
didn't recall the details of the answer. Do note that both of the
citations above are to versions that were not yet officially accepted,
so they are not definitive. However, on checking f2008, I see that the
edit suggested in N1805 was incorporated.

So that means that the above code is valid, which in turn means that it
is a bug for Intel to fail it. I suspect Intel probably put in that
check before the interp passed.

herrman...@gmail.com

unread,
Feb 7, 2017, 10:58:08 PM2/7/17
to
On Tuesday, February 7, 2017 at 11:17:30 AM UTC-8, Richard Maine wrote:

(regarding)

> > > 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)


(I wrote)

> > As well as I understand, it isn't conforming as of F2008, though
> > that doesn't mean it won't work.

> Why not? I don't see anything that it violates. The part of your post
> that I elided discussed how C pointers can differ from Fortran ones.
> That would certainly be relevant if the OP were trying to do either the
> allocate or the deallocate in C. But he isn't.

I was considering "Deallocating a pointer that is disassociated or
whose target was not created by an ALLOCATE statement causes
an error condition in the DEALLOCATE statement."

> The allocation of "a" is done by a Fortran allocate.

> His b is a Fortran pointer - not a C one. The fact that C code was
> involved in the process of getting it defined seem irrelevant. I see no
> restriction on the order of "was C ever involved?" However it got
> defined, it is, before the deallocate, a valid Fortran pointer. It is of
> the right type, type parameters, and shape, and points at the whole of
> the allocated object.

b was created by C_F_POINTER, not by ALLOCATE, and not by
pointer assignment to a pointer from ALLOCATE.

It could be that it is the same as a Fortran pointer assignment
of a to b, but that isn't so obvious to me.

> I'm willing to stand corrected if you can point to an actual restriction
> that it violates, but I don't see one.

This gets to a question on how to read the standard. Does the
standard describe what is allowed, or what is not disallowed?

I don't see a statement that allows DEALLOCATE on a pointer
from C_F_POINTER, but also no statement that disallows it.

Hopefully not getting too far off, this reminds me of Thomas
Jefferson and the US Constitution. Does the constitution
say what the government is allowed to do, or what it isn't
disallowed from doing?

As to the actual problem, and considering possible
implementations, (yes, I know what you think about that),
does ALLOCATE just malloc() the needed space, or can it
do other things?

But okay, some of those things would also have to be
done by C_F_POINTER, and there doesn't seem to be
a specific way to undo C_F_POINTER, so maybe it can't
do anything else.

herrman...@gmail.com

unread,
Feb 7, 2017, 11:51:59 PM2/7/17
to
On Tuesday, February 7, 2017 at 2:57:40 PM UTC-8, Richard Maine wrote:
> FortranFan <parek...@gmail.com> wrote:

> > I think this code is standard-conforming too; what Intel Fortran is doing
> > is providing the diagnostics that it is able to recognize, that the
> > action to deallocate the anonymous target associated with b was
> > allocated and associated with a separate object. But I don't think the
> > processor is required to do so by the standard.

> I have some uncertainty as to whether or not James' example is standard
> conforming. I think probably not, but I'm a little uncertain. See my
> reply to him.

> But the Intel compiler is not giving a warning. It is a fatal error at
> run time. If the code were standard conforming, then that would be an
> error in the compiler. Compilers are not allowed to refuse to run
> standard conforming code because it thinks something is questionable.
> They may provide warnings, but they can't refuse to run the code.

OK, to continue my previous discussion, yes for the OP question,
the bits where data are stored were allocated by Fortran, but the
compiler and library have no way to know that. They could have
been allocated my malloc() in the OP's C code.

If a compiler wants to do strict checking, it should disallow
DEALLOCATE on such, similar to the way that the bits are the
same for an array section that is the whole array.

An array pointer might have bits that indicate its source
being ALLOCATE or C_F_POINTER.

As for the OP, my thought is that instead of C_LOC on
the pointer, use C_LOC on a structure containing the
pointer, which should get all bits of the pointer through.

Then C_F_POINTER a pointer to the structure, and
DEALLOCATE the structure member. I presume there
is no question about copies of structures containing
pointers, but I suppose I don't know that.

But they will be the same actual bits.

More interesting is a C copy of a structure containing
pointers, where it is a copy of all the bits, but not the
original bits.

> Note also that deallocating a pointer that was allocated via some other
> variable is completely ordinary. That is done with pointers all the
> time. I guarantee that the Intel compiler doesn't fail or warn about
> that in general because if it did, I'd have noticed with many of my
> codes. The problem here has nothing to do with it being some other
> variable, but with the slice.

Yes, presumably any magic bits get copied that way.

> Say, I've still got that example sitting in a file handy here, so I can
> directly test that instead of just saying what I'm sure to be the
> case....
>
> Yep. Change the

(snip)

-- glen

Richard Maine

unread,
Feb 7, 2017, 11:57:37 PM2/7/17
to
<herrman...@gmail.com> wrote:

> On Tuesday, February 7, 2017 at 11:17:30 AM UTC-8, Richard Maine wrote:
>
> (regarding)
>
> > > > 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)
>
>
> (I wrote)
>
> > > As well as I understand, it isn't conforming as of F2008, though
> > > that doesn't mean it won't work.
>
> > Why not?

> I was considering "Deallocating a pointer that is disassociated or
> whose target was not created by an ALLOCATE statement causes
> an error condition in the DEALLOCATE statement."
>
> > The allocation of "a" is done by a Fortran allocate.
>
> > His b is a Fortran pointer - not a C one. The fact that C code was
> > involved in the process of getting it defined seem irrelevant. I see no
> > restriction on the order of "was C ever involved?" However it got
> > defined, it is, before the deallocate, a valid Fortran pointer. It is of
> > the right type, type parameters, and shape, and points at the whole of
> > the allocated object.
>
> b was created by C_F_POINTER, not by ALLOCATE, and not by
> pointer assignment to a pointer from ALLOCATE.

Reread the restriction more carefully. It is about how the *TARGET* was
created, not how the pointer was created. The target of b was created by
an allocate. And nothing in that restriction mentions either pointer
assignment or C_F_POINTER at all, so pointer assignment vs C_F_POINTER
is irrelevant.

> This gets to a question on how to read the standard. Does the
> standard describe what is allowed, or what is not disallowed?

Both. That depends on context. I don't think I can answer that in full
generality - certainly not in the space of a usenet posting. The best
answer is what the standard itself says on the subject. See section 1.5
on conformance. In particular the first sentence therein. From f95

"A program is a standard-conforming program if it uses only
those forms and relationships described herein and if the program
has an interpretation according to this standard."

Certainly the syntax defines things in terms of what is allowed. You
can't just type in random garbage and say that it must be standard
conforming because nothing disallows it. That's the part about using
"only the forms and relationships described herein." But if something
conforms to the standard's syntax and has an interpretation in the
standard, then you are mostly in the realm of being standard conforming
unless there is a resriction against it.

Anything else would be completely impractical. Let's move away from
pointers because some people get more confused by them. Just ordinary
scalar variables. There is nothing that says you can print the value of
a variable whose value was defined by a READ statement. So does that
mean you can't and that it is only allowed to print the value of a
variable that was defined by an assignment statement? I think we all
know the answer to that. The standard just doesn't work that way.

And back to the example at hand. If you wonder whether C_F_POINTER is ok
because you don't see anything explicitly allowing that, then why do you
think pointer assigbnment is automatically ok? There isn't anything
explicitly allowing that either. The words just talk about how the
target was created - nothing about how the pointer got associated with
that target. I see no difference except that one case might be more
familliar to you and that you might imagine implementations that
wouldn't work on the other case. Neither of those constitute ways
tointerpret the standard.

> As to the actual problem, and considering possible
> implementations, (yes, I know what you think about that),
> does ALLOCATE just malloc() the needed space, or can it
> do other things?

Of course it can do other things, and there are implementations where it
does. For example, see garbage collection - not in the standard, which
doesn't get into that, but in actual implementations.

Richard Maine

unread,
Feb 8, 2017, 12:15:27 AM2/8/17
to
<herrman...@gmail.com> wrote:

> OK, to continue my previous discussion, yes for the OP question,
> the bits where data are stored were allocated by Fortran, but the
> compiler and library have no way to know that. They could have
> been allocated my malloc() in the OP's C code.

Many things could corrupt data in all sorts of ways. That's not the
question.

> If a compiler wants to do strict checking, it should disallow
> DEALLOCATE on such, similar to the way that the bits are the
> same for an array section that is the whole array.

No, compilers are not supposed to disallow standard conforming things
just because they imagine that there might be a way that they could go
wrong. And things don't violate the standard just because there is a way
they could go wrong. (By that logic, all procedure calls without
explicit interfaces should be thrown out).

The question has nothing to do with what bits might or might not be
around. Yes, I'm going to say that you are looking too much at
implementation matters. The standard says nothing about the bits in
question or ways that potentially invalid bits might creep in.

Per my other post, if the standard defines what it means and doesn't
otherwise prohibit it, then the compiler is supposed to make it work -
not just say that it might go wrong so we'll disallow it. If it is
impractical for compilers to make it work, then the standard writers
screwed up. If the likelihod of things going wrong is excessive, then
one might question the judgement of the standard writers. Both of those
are potentially things to bring up as interpretation questions, but they
don't constitute reasons to unilaterally ignore what the standard says.

> More interesting is a C copy of a structure containing
> pointers, where it is a copy of all the bits, but not the
> original bits.

And you have an example of that which comes even close to conforming to
the standard? You really do need to pay at least some attention to what
the standard says if you want to answer questions about standard
conformance. Note that a stucture containing Fortran pointers is not
interoperable; that pretty much kills most of the trivial examples in
terms of standard conformance. Let me also note that there are reasons
that such structures are not interoperable, and that those reasons are
related to this issue.

F2015 has some stuff relating to such structures, but I haven't looked
at that enough to comment usefully.

herrman...@gmail.com

unread,
Feb 8, 2017, 12:35:30 AM2/8/17
to
On Tuesday, February 7, 2017 at 9:15:27 PM UTC-8, Richard Maine wrote:

(snip, then I wrote)

> > More interesting is a C copy of a structure containing
> > pointers, where it is a copy of all the bits, but not the
> > original bits.

Leaving the previous question aside for now ...

> And you have an example of that which comes even close to conforming to
> the standard? You really do need to pay at least some attention to what
> the standard says if you want to answer questions about standard
> conformance. Note that a stucture containing Fortran pointers is not
> interoperable; that pretty much kills most of the trivial examples in
> terms of standard conformance. Let me also note that there are reasons
> that such structures are not interoperable, and that those reasons are
> related to this issue.

From F2008 for C_F_POINTER:

"If the value of CPTR is the result of a reference to C LOC with a
noninteroperable argument X, FPTR shall be a nonpolymorphic
scalar pointer with the same type and type parameters as X."

If I pass a C_LOC value to C, and pass the exact same value back,
I should be able to use it with C_F_POINTER, just as if I did it
without passing it through C.

Richard Maine

unread,
Feb 8, 2017, 12:42:44 AM2/8/17
to
Ok. But I don't see how that is going to involve copying the bits of the
structure without going outside of the standards. That's going to be a
pointer to the same bits - not to a copy of them. You might (and indeed
likely do) have a copy of the bits that oint to the structure, but not a
copy of the bits within the structure.

herrman...@gmail.com

unread,
Feb 8, 2017, 5:01:31 AM2/8/17
to
On Tuesday, February 7, 2017 at 9:42:44 PM UTC-8, Richard Maine wrote:

(snip, I wrote)
> > If I pass a C_LOC value to C, and pass the exact same value back,
> > I should be able to use it with C_F_POINTER, just as if I did it
> > without passing it through C.

> Ok. But I don't see how that is going to involve copying the bits of the
> structure without going outside of the standards. That's going to be a
> pointer to the same bits - not to a copy of them. You might (and indeed
> likely do) have a copy of the bits that oint to the structure, but not a
> copy of the bits within the structure.

As for the OP, yes, a pointer to the exact same bits should be fine.

The C feature that many other languages don't have, is that you
can operate on data without knowing its actual contents.

You can, for example, sort an array of struct knowing just the length
(sizeof) each array element. This is the way qsort() is designed to work.

It should be possible with C_LOC and C_SIZEOF to pass a Fortran
structure array to qsort() and sort it. Should that work even when
the structure has pointers?

Richard Maine

unread,
Feb 8, 2017, 5:37:33 AM2/8/17
to
<herrman...@gmail.com> wrote:

> It should be possible with C_LOC and C_SIZEOF to pass a Fortran
> structure array to qsort() and sort it. Should that work even when
> the structure has pointers?

Did you note the word "scalar" in the bit from f2008 that you posted?

herrman...@gmail.com

unread,
Feb 8, 2017, 6:55:04 AM2/8/17
to
On Wednesday, February 8, 2017 at 2:37:33 AM UTC-8, Richard Maine wrote:

(snip, I wrote)
> > It should be possible with C_LOC and C_SIZEOF to pass a Fortran
> > structure array to qsort() and sort it. Should that work even when
> > the structure has pointers?

> Did you note the word "scalar" in the bit from f2008 that you posted?

I suppose we are discussing too many things at the same time,
but at that point it was a single (scalar) structure containing an
array pointer.

Not being completely sure what the OP is trying to do, I was
figuring that he has a C main program that calls two Fortran
subroutines. One allocates an array, and then passes it,
indirectly through a C main, to another. If a C_PTR to the
(scalar) structure is passed, then C_F_POINTER is used, the
second one has access to the original pointer.

For a reply to the other question, see below.

herrman...@gmail.com

unread,
Feb 8, 2017, 7:58:57 AM2/8/17
to
On Wednesday, February 8, 2017 at 2:37:33 AM UTC-8, Richard Maine wrote:

(snip)

> > It should be possible with C_LOC and C_SIZEOF to pass a Fortran
> > structure array to qsort() and sort it. Should that work even when
> > the structure has pointers?

> Did you note the word "scalar" in the bit from f2008 that you posted?

The way sizeof works in C, is that it is the sizeof something,
such as a struct, including any padding needed for an array.

That is:


struct st {int i, double d} s[3];

(unsigned char*)(s+2)-(unsigned char*)(s+1)

is equal to sizeof(struct st) and sizeof(s[0])

This allows one to index through an array, generating
pointers to each element, without knowing the contents
of the array.

As for your question about scalars, you could generate
scalars in a loop, and pointer assign them to structure
members.

Ian Harvey

unread,
Feb 8, 2017, 4:49:29 PM2/8/17
to
Note that a Fortran derived type with Fortran pointer components cannot
be interoperable (F2008 C1505). The argument to C_SIZEOF must be
interoperable, and there is no guarantee that the result from calling
C_LOC on an object that is not of interoperable type be a C pointer that
C may actually dereference. So what you suggest is not possible.

Consider all the silliness that you can do, without leaving Fortran,
with TRANSFER. In the general case, these games will also fail in the
face of pointer or allocatable components.



herrman...@gmail.com

unread,
Feb 9, 2017, 1:06:04 AM2/9/17
to
On Wednesday, February 8, 2017 at 1:49:29 PM UTC-8, Ian Harvey wrote:

(snip)

> Note that a Fortran derived type with Fortran pointer components cannot
> be interoperable (F2008 C1505). The argument to C_SIZEOF must be
> interoperable, and there is no guarantee that the result from calling
> C_LOC on an object that is not of interoperable type be a C pointer that
> C may actually dereference. So what you suggest is not possible.

As I noted above, at least since F2008 you can C_LOC a non-interoperable
scalar, and C_F_POINTER it back to a Fortran pointer.

Ian Harvey

unread,
Feb 9, 2017, 3:03:41 PM2/9/17
to
On 2017-02-09 17:06, herrman...@gmail.com wrote:
> On Wednesday, February 8, 2017 at 1:49:29 PM UTC-8, Ian Harvey wrote:
>
> (snip)
>
>> Note that a Fortran derived type with Fortran pointer components cannot
>> be interoperable (F2008 C1505). The argument to C_SIZEOF must be
>> interoperable, and there is no guarantee that the result from calling
>> C_LOC on an object that is not of interoperable type be a C pointer that
>> C may actually dereference. So what you suggest is not possible.
>
> As I noted above, at least since F2008 you can C_LOC a non-interoperable
> scalar, and C_F_POINTER it back to a Fortran pointer.

The round trip guarantee (subject to the other restrictions on the
argument to C_LOC) from C_LOC to C_F_POINTER is available in Fortran 2003.

But that doesn't mean you can *dereference* the result of calling C_LOC
on a thing that is not interoperable *from within C*. Something like
qsort isn't going to be able to do much if it cannot deference the base
address of the thing you want to sort.

See F2008 note 15.6 or F2008 note 15.5.


James Van Buskirk

unread,
Feb 9, 2017, 9:30:27 PM2/9/17
to
"Ian Harvey" wrote in message news:o7ihrf$n1c$1...@dont-email.me...

> But that doesn't mean you can *dereference* the result of calling C_LOC on
> a thing that is not interoperable *from within C*. Something like qsort
> isn't going to be able to do much if it cannot deference the base address
> of the thing you want to sort.

> See F2008 note 15.6 or F2008 note 15.5.

C doesn't have any problem with opaque handles. qsort() just passes them
along to to the compar() function, written in Fortran and passed as an
actual
argument to qsort() thus determining the precedence of elements of the base
array without examining their contents. I have definitely posted code using
qsort() through interoperability to clf, either look them up or just think
about
it little.

Ian Harvey

unread,
Feb 10, 2017, 5:03:16 PM2/10/17
to
There's a bit more going on than qsort "just passing them along"... in
non-trivial cases (lets assume the size of the array being sorted is
greater than one), qsort does pointer arithmetic to generate pointers
that reference particular elements in the array, and if the elements in
the array need to be shuffled around then qsort does pointer
dereferencing (including dereferencing the values that result through
pointer arithmetic). If the thing that qsort starts working with isn't
actually a valid C pointer, then all that malarkey may go horribly wrong.

For calls to library functions, the C standard explicitly requires that
pointers passed as arguments that correspond to arrays have a value
"such that all address computations and accesses to objects ... are in
fact valid". There's no requirement that the "opaque handle" returned
by C_LOC, for something that isn't interoperable, meets that requirement.

If the thing being C_LOC'd is interoperable... no problems.

Practically, all the implementations I am aware of stuff a machine
pointer into the C_PTR that pops out of calling C_LOC, regardless of
whether the argument is interoperable or not, and the companion C
processors all use machine pointers as the representation of a C
pointer, but that's all implementation detail.

My point, which has perhaps been lost, was that from the perspective of
the standard, a discussion around whether qsort works on an array (or
scalar - but that doesn't make any sense to begin with) of objects of
some type with a Fortran pointer component is moot - you are comfortably
in "anything can happen" territory.

herrman...@gmail.com

unread,
Feb 12, 2017, 10:01:29 PM2/12/17
to
On Friday, February 10, 2017 at 2:03:16 PM UTC-8, Ian Harvey wrote:
> On 2017-02-10 13:30, James Van Buskirk wrote:
> > "Ian Harvey" wrote in message news:o7ihrf$n1c$1...@dont-email.me...

> >> But that doesn't mean you can *dereference* the result of calling
> >> C_LOC on a thing that is not interoperable *from within C*. Something
> >> like qsort isn't going to be able to do much if it cannot deference
> >> the base address of the thing you want to sort.
> >> See F2008 note 15.6 or F2008 note 15.5.

> > C doesn't have any problem with opaque handles. qsort() just passes them
> > along to to the compar() function, written in Fortran and passed as an
> > actual argument to qsort() thus determining the precedence of
> > elements of the base array without examining their contents.
> > I have definitely posted code using
> > qsort() through interoperability to clf, either look them up or just
> > think about it little.

> There's a bit more going on than qsort "just passing them along"... in
> non-trivial cases (lets assume the size of the array being sorted is
> greater than one), qsort does pointer arithmetic to generate pointers
> that reference particular elements in the array, and if the elements in
> the array need to be shuffled around then qsort does pointer
> dereferencing (including dereferencing the values that result through
> pointer arithmetic). If the thing that qsort starts working with isn't
> actually a valid C pointer, then all that malarkey may go horribly wrong.

There are some things that C requires. One is that you can cast
a pointer to (unsigned char *), and then dereference that pointer,
to copy some memory region, using the sizeof operator to
determine how many bytes (C term, which doesn't have to be 8 bits)
to copy.

> For calls to library functions, the C standard explicitly requires that
> pointers passed as arguments that correspond to arrays have a value
> "such that all address computations and accesses to objects ... are in
> fact valid". There's no requirement that the "opaque handle" returned
> by C_LOC, for something that isn't interoperable, meets that requirement.

You have to be able to pass a C_LOC to C, or it isn't very useful.

Also, arrays passed to C, as for assumed size in Fortran, have
to be contiguous. C doesn't know about discontiguous arrays.

It might be that C_SIZEOF doesn't always give the right size,
though that would seem a bug to me. If it doesn't, use C_LOC
on two consecutive array elements, pass those to C where they
can be cast to (unsigned char *) and subtracted.

> If the thing being C_LOC'd is interoperable... no problems.

As noted above, there are requirements on scalars, C_LOC
and C_F_POINTER, even for non-interoperable data.

You could pass an array of C_LOC to C (or pass them one at
a time), then process them in C.

> Practically, all the implementations I am aware of stuff a machine
> pointer into the C_PTR that pops out of calling C_LOC, regardless of
> whether the argument is interoperable or not, and the companion C
> processors all use machine pointers as the representation of a C
> pointer, but that's all implementation detail.

I have wondered some about C implementations that don't
put a machine address into a pointer. Specifically, I have
wondered about JVM code as target for a C compiler.

There is a C requirement that you do pointer arithmetic only
for pointers to the same data object. You can't subtract
pointers to elements of different arrays, for example.

> My point, which has perhaps been lost, was that from the perspective of
> the standard, a discussion around whether qsort works on an array (or
> scalar - but that doesn't make any sense to begin with) of objects of
> some type with a Fortran pointer component is moot - you are comfortably
> in "anything can happen" territory.

I often enough do call qsort() with struct, but many people don't.
For small arrays, I usually don't worry, but some people find the time
required to do the copy to be too much (even though it usually isn't)
and instead sort arrays of pointers to the data objects.

If you somehow don't believe that one can qsort() an array of
Fortran structures, you should still be able to sort an array of
C_LOC. That is, of C pointers copied from C_LOC.

0 new messages